Commit 9ba731c2 authored by Alfranio Correia's avatar Alfranio Correia

BUG#51894 Replication failure with SBR on DROP TEMPORARY TABLE inside a

          transaction
BUG#52616 Temp table prevents switch binlog format from STATEMENT to ROW

Before the WL#2687 and BUG#46364, every non-transactional change that happened
after a transactional change was written to trx-cache and flushed upon
committing the transaction. WL#2687 and BUG#46364 changed this behavior and
non-transactional changes are now written to the binary log upon committing
the statement.

A binary log event is identified as transactional or non-transactional through
a flag in the Log_event which is set taking into account the underlie storage
engine on what it is stems from. In the current bug, this flag was not being
set properly when the DROP TEMPORARY TABLE was executed.

However, while fixing this bug we figured out that changes to temporary tables
should be always written to the trx-cache if there is an on-going transaction.
Otherwise, binlog events in the reversed order would be produced.

Regarding concurrency, keeping changes to temporary tables in the trx-cache is
also safe as temporary tables are only visible to the owner connection.

In this patch, we classify the following statements as unsafe:
   1 - INSERT INTO t_myisam SELECT * FROM t_myisam_temp

   2 - INSERT INTO t_myisam_temp SELECT * FROM t_myisam

   3 - CREATE TEMPORARY TABLE t_myisam_temp SELECT * FROM t_myisam

On the other hand, the following statements are classified as safe:

   1 - INSERT INTO t_innodb SELECT * FROM t_myisam_temp

   2 - INSERT INTO t_myisam_temp SELECT * FROM t_innodb

The patch also guarantees that transactions that have a DROP TEMPORARY are
always written to the binary log regardless of the mode and the outcome:
commit or rollback. In particular, the DROP TEMPORARY is extended with the
IF EXISTS clause when the current statement logging format is set to row.

Finally, the patch allows to switch from STATEMENT to MIXED/ROW when there
are temporary tables but the contrary is not possible.
parent 4ca8066f
......@@ -142,13 +142,13 @@ BEGIN;
--eval INSERT INTO t1 (a, data) VALUES (21, 's');
--enable_query_log
if (`SELECT @@binlog_format = 'STATEMENT'`)
if (`SELECT @@binlog_format = 'STATEMENT' || @@binlog_format = 'MIXED'`)
{
--disable_query_log
CREATE TABLE t4 SELECT * FROM t1;
--enable_query_log
}
if (`SELECT @@binlog_format = 'ROW' || @@binlog_format = 'MIXED'`)
if (`SELECT @@binlog_format = 'ROW'`)
{
--disable_query_log
--error ER_TRANS_CACHE_FULL, ER_ERROR_ON_WRITE
......@@ -178,7 +178,7 @@ BEGIN;
CREATE TABLE t5 (a int);
--enable_query_log
if (`SELECT @@binlog_format = 'ROW' || @@binlog_format = 'MIXED'` )
if (`SELECT @@binlog_format = 'ROW'`)
{
connection slave;
--source include/wait_for_slave_sql_to_stop.inc
......
......@@ -362,10 +362,8 @@ while (`SELECT $ddl_cases >= 1`)
#
# 1: BEGIN
# 2: CREATE TEMPORARY
# 3: COMMIT
# 4: BEGIN
# 5: INSERT
# 6: COMMIT
# 3: INSERT
# 4: COMMIT
#
# In RBR the transaction is not committed either and the statement is not
# written to the binary log:
......@@ -377,7 +375,7 @@ while (`SELECT $ddl_cases >= 1`)
#
if (`select @@binlog_format = 'STATEMENT' || @@binlog_format = 'MIXED'` )
{
let $commit_event_row_number= 6;
let $commit_event_row_number= 4;
}
#
# In NDB (RBR mode), the commit event is the sixth event
......@@ -488,11 +486,9 @@ while (`SELECT $ddl_cases >= 1`)
# In SBR, we have what follows:
#
# 1: BEGIN
# 2: DROP TEMPORARY
# 3: COMMIT
# 4: BEGIN
# 5: INSERT
# 6: COMMIT
# 2: INSERT
# 3: DROP TEMPORARY
# 4: COMMIT
#
# In RBR the transaction is not committed either and the statement is not
# written to the binary log:
......@@ -503,10 +499,6 @@ while (`SELECT $ddl_cases >= 1`)
# 4: COMMIT
#
if (`select @@binlog_format = 'STATEMENT'`)
{
let $commit_event_row_number= 6;
}
if (`select @@binlog_format = 'ROW'`)
{
let $commit_event_row_number= 4;
}
......@@ -518,7 +510,7 @@ while (`SELECT $ddl_cases >= 1`)
# 4: DROP TEMPORARY table IF EXISTS
# 5: COMMIT
#
if (`select @@binlog_format = 'MIXED'`)
if (`select @@binlog_format = 'MIXED' || @@binlog_format = 'ROW'`)
{
let $commit_event_row_number= 5;
}
......@@ -527,15 +519,18 @@ while (`SELECT $ddl_cases >= 1`)
# in the binary log:
#
# 1: BEGIN
# 2: TABLE MAP EVENT
# 3: TABLE MAP EVENT (ndb_apply_status)
# 4: ROW EVENT
# 5: ROW EVENT
# 6: COMMIT
# 2: DROP TEMPORARY table IF EXISTS
# 3: COMMIT
# 4: BEGIN
# 5: TABLE MAP EVENT
# 6: TABLE MAP EVENT (ndb_apply_status)
# 7: ROW EVENT
# 8: ROW EVENT
# 9: COMMIT
#
if (`SELECT '$engine' = 'NDB'`)
{
let $commit_event_row_number= 6;
let $commit_event_row_number= 9;
}
#
# In NDB (MIXED mode), the commit event is the nineth event
......
......@@ -78,10 +78,6 @@ connection slave;
# the transaction to be logged. Since t1 is non-transactional on
# slave, the change will not be rolled back, so the inserted rows will
# stay in t1 and we can verify that the transaction was replicated.
#
# Note, however, that the previous explanation is not true for ROW and
# MIXED modes as rollback on a transactional table is not written to
# the binary log.
ALTER TABLE mysqltest1.t1 ENGINE = MyISAM;
SHOW CREATE TABLE mysqltest1.t1;
......@@ -92,14 +88,14 @@ DROP TEMPORARY TABLE mysqltest1.tmp;
ROLLBACK;
--error ER_NO_SUCH_TABLE
SHOW CREATE TABLE mysqltest1.tmp;
# Must return no rows here
--echo ######### Must return no rows here #########
SELECT COUNT(*) FROM mysqltest1.t1;
INSERT INTO mysqltest1.t1 SET f1= 2;
CREATE TEMPORARY TABLE mysqltest1.tmp2(a INT);
ROLLBACK;
SHOW CREATE TABLE mysqltest1.tmp2;
# Must return no rows here
--echo ######### Must return no rows here #########
SELECT COUNT(*) FROM mysqltest1.t1;
sync_slave_with_master;
......@@ -109,7 +105,7 @@ connection slave;
SHOW CREATE TABLE mysqltest1.tmp;
--error ER_NO_SUCH_TABLE
SHOW CREATE TABLE mysqltest1.tmp2;
# t1 has two rows here: the transaction not rolled back since t1 uses MyISAM
--echo ######### t1 has two rows here: the transaction not rolled back since t1 uses MyISAM #########
SELECT COUNT(*) FROM mysqltest1.t1;
FLUSH LOGS;
......
......@@ -18,6 +18,10 @@ connection slave;
reset master;
connection master;
--disable_query_log
CALL mtr.add_suppression("Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT");
--enable_query_log
# MTR is not case-sensitive.
let $lower_stmt_head= load data;
let $UPPER_STMT_HEAD= LOAD DATA;
......@@ -40,7 +44,9 @@ create temporary table t2 (day date,id int(9),category enum('a','b','c'),name va
eval $lower_stmt_head infile '../../std_data/rpl_loaddata2.dat' into table t2 fields terminated by ',' optionally enclosed by '%' escaped by '@' lines terminated by '\n##\n' starting by '>' ignore 1 lines;
create table t3 (day date,id int(9),category enum('a','b','c'),name varchar(60));
--disable_warnings
insert into t3 select * from t2;
--enable_warnings
save_master_pos;
connection slave;
......
CREATE TABLE t1 (a CHAR(1)) CHARACTER SET utf8;
INSERT INTO t1 VALUES ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7');
INSERT INTO t1 VALUES ('8'),('9'),('A'),('B'),('C'),('D'),('E'),('F');
--disable_warnings
#
# Populate tables head and tail with values '00'-'FF'
#
......@@ -40,5 +42,6 @@ AND (middle BETWEEN '80' AND 'BF')
AND (tail BETWEEN '80' AND 'BF')
AND NOT (head='E0' AND middle BETWEEN '80' AND '9F')
ORDER BY head, middle, tail;
--disable_warnings
SELECT count(*) FROM t1;
......@@ -37,20 +37,23 @@ Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 514 Query 1 581 BEGIN
master-bin.000001 581 Query 1 788 use `mtr`; INSERT INTO test_suppressions (pattern) VALUES ( NAME_CONST('pattern',_latin1'Error in Log_event::read_log_event()' COLLATE 'latin1_swedish_ci'))
master-bin.000001 788 Query 1 856 COMMIT
master-bin.000001 856 Query 1 1019 use `test`; CREATE TABLE t4 (s1 CHAR(50) CHARACTER SET latin1,
master-bin.000001 856 Query 1 923 BEGIN
master-bin.000001 923 Query 1 1172 use `mtr`; INSERT INTO test_suppressions (pattern) VALUES ( NAME_CONST('pattern',_latin1'Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT' COLLATE 'latin1_swedish_ci'))
master-bin.000001 1172 Query 1 1240 COMMIT
master-bin.000001 1240 Query 1 1403 use `test`; CREATE TABLE t4 (s1 CHAR(50) CHARACTER SET latin1,
s2 CHAR(50) CHARACTER SET cp932,
d DECIMAL(10,2))
master-bin.000001 1019 Query 1 1265 use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `bug18293`(IN ins1 CHAR(50),
master-bin.000001 1403 Query 1 1649 use `test`; CREATE DEFINER=`root`@`localhost` PROCEDURE `bug18293`(IN ins1 CHAR(50),
IN ins2 CHAR(50) CHARACTER SET cp932,
IN ind DECIMAL(10,2))
BEGIN
INSERT INTO t4 VALUES (ins1, ins2, ind);
END
master-bin.000001 1265 Query 1 1333 BEGIN
master-bin.000001 1333 Query 1 1597 use `test`; INSERT INTO t4 VALUES ( NAME_CONST('ins1',_latin1 0x466F6F2773206120426172 COLLATE 'latin1_swedish_ci'), NAME_CONST('ins2',_cp932 0xED40ED41ED42 COLLATE 'cp932_japanese_ci'), NAME_CONST('ind',47.93))
master-bin.000001 1597 Query 1 1666 COMMIT
master-bin.000001 1666 Query 1 1752 use `test`; DROP PROCEDURE bug18293
master-bin.000001 1752 Query 1 1828 use `test`; DROP TABLE t4
master-bin.000001 1649 Query 1 1717 BEGIN
master-bin.000001 1717 Query 1 1981 use `test`; INSERT INTO t4 VALUES ( NAME_CONST('ins1',_latin1 0x466F6F2773206120426172 COLLATE 'latin1_swedish_ci'), NAME_CONST('ins2',_cp932 0xED40ED41ED42 COLLATE 'cp932_japanese_ci'), NAME_CONST('ind',47.93))
master-bin.000001 1981 Query 1 2050 COMMIT
master-bin.000001 2050 Query 1 2136 use `test`; DROP PROCEDURE bug18293
master-bin.000001 2136 Query 1 2212 use `test`; DROP TABLE t4
End of 5.0 tests
SHOW BINLOG EVENTS FROM 490;
ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Wrong offset or I/O error
......@@ -75,7 +78,11 @@ CREATE TABLE t1 (b VARCHAR(2));
INSERT INTO t1 VALUES ('0'),('1'),('2'),('3'),('4'),('5'),('6'),('7');
INSERT INTO t1 VALUES ('8'),('9'),('A'),('B'),('C'),('D'),('E'),('F');
CREATE TEMPORARY TABLE head AS SELECT concat(b1.b, b2.b) AS head FROM t1 b1, t1 b2;
Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
CREATE TEMPORARY TABLE tail AS SELECT concat(b1.b, b2.b) AS tail FROM t1 b1, t1 b2;
Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
DROP TABLE t1;
CREATE TABLE t1 AS
SELECT concat(head, tail) AS code, ' ' AS a
......
......@@ -118,6 +118,7 @@ master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `tt1` /* generated by server */
FLUSH STATUS;
show databases;
Database
......
......@@ -57,4 +57,5 @@ DROP TEMPORARY TABLE t1;
###############################################
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `t1` /* generated by server */
###############################################
......@@ -8,14 +8,14 @@ INSERT INTO t1b VALUES (1,1), (1,2), (2,1), (2,2);
INSERT INTO t1m VALUES (1,1), (1,2), (2,1), (2,2);
UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c;
Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
The last event before the COMMIT is use `test`; UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c
*** Please look in binlog_multi_engine.test if you have a diff here ****
START TRANSACTION;
INSERT INTO t1n VALUES (1,1), (1,2), (2,1), (2,2);
UPDATE t1m, t1n SET m = 2, e = 3 WHERE n = f;
Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
UPDATE t1n, t1b SET e = 2, b = 3 WHERE f = c;
COMMIT;
TRUNCATE t1m;
......
......@@ -1133,6 +1133,7 @@ COERCIBILITY(NAME_CONST('s1', _utf8'test' COLLATE utf8_unicode_ci)) d2,
COERCIBILITY(s1) d3;
DROP TEMPORARY TABLE tmp1;
END
master-bin.000001 # Query # # use `bug39182`; DROP TEMPORARY TABLE IF EXISTS `tmp1` /* generated by server */
DROP PROCEDURE p1;
DROP TABLE t1;
DROP DATABASE bug39182;
......@@ -1254,6 +1255,7 @@ master-bin.000001 # Table_map # # table_id: # (mysql.user)
master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; DROP TABLE `t1`,`t2`,`t3` /* generated by server */
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `tt1` /* generated by server */
master-bin.000001 # Query # # use `test`; create table t1 (a int not null auto_increment, primary key (a)) engine=myisam
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
......
......@@ -27,6 +27,10 @@ show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # CREATE DATABASE `drop-temp+table-test`
master-bin.000001 # Query # # use `drop-temp+table-test`; CREATE TABLE t(c1 int)
master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TEMPORARY TABLE IF EXISTS `tmp` /* generated by server */
master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TEMPORARY TABLE IF EXISTS `tmp1` /* generated by server */
master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TEMPORARY TABLE IF EXISTS `tmp3` /* generated by server */
master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TABLE IF EXISTS `t` /* generated by server */
master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TEMPORARY TABLE IF EXISTS `tmp2` /* generated by server */
master-bin.000001 # Query # # use `drop-temp+table-test`; DROP TABLE IF EXISTS tmp2, t
DROP DATABASE `drop-temp+table-test`;
......@@ -420,6 +420,7 @@ master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; DROP TABLE `t1` /* generated by server */
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `t2` /* generated by server */
reset master;
create table t1 (a int) engine=innodb;
create table t2 (a int) engine=myisam;
......
......@@ -639,9 +639,7 @@ COERCIBILITY(NAME_CONST('s1', _utf8'test' COLLATE utf8_unicode_ci)) d2,
COERCIBILITY(s1) d3;
DROP TEMPORARY TABLE tmp1;
END
master-bin.000001 # Query # # use `bug39182`; CREATE TEMPORARY TABLE tmp1
SELECT * FROM t1 WHERE a LIKE CONCAT("%", NAME_CONST('s1',_utf8'test' COLLATE 'utf8_unicode_ci'), "%")
master-bin.000001 # Query # # use `bug39182`; DROP TEMPORARY TABLE tmp1
master-bin.000001 # Query # # use `bug39182`; DROP TEMPORARY TABLE IF EXISTS `tmp1` /* generated by server */
DROP PROCEDURE p1;
DROP TABLE t1;
DROP DATABASE bug39182;
......
......@@ -28,6 +28,10 @@
source include/have_log_bin.inc;
source include/have_binlog_format_mixed_or_statement.inc;
--disable_query_log
CALL mtr.add_suppression("Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT");
--enable_query_log
connect (master,127.0.0.1,root,,test,$MASTER_MYPORT,);
connect (master1,127.0.0.1,root,,test,$MASTER_MYPORT,);
......@@ -55,10 +59,12 @@ delete from tmp1_foo where a < 5;
connection master1;
delete from tmp2_foo where a < 5;
--disable_warnings
connection master;
insert into foo select * from tmp1_foo;
connection master1;
insert into foo select * from tmp2_foo;
--enable_warnings
connection master;
truncate table tmp1_foo;
......
......@@ -9,12 +9,12 @@ INSERT INTO t1 VALUES (1,1), (1,2), (2,1), (2,2);
INSERT INTO t2 VALUES (1,1), (1,2), (2,1), (2,2);
UPDATE t1, t2 SET m = 2, b = 3 WHERE n = c;
Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
START TRANSACTION;
INSERT INTO t3 VALUES (1,1), (1,2), (2,1), (2,2);
UPDATE t1, t3 SET m = 2, e = 3 WHERE n = f;
Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
UPDATE t3, t2 SET e = 2, b = 3 WHERE f = c;
COMMIT;
show binlog events from <binlog_start>;
......
......@@ -22,7 +22,7 @@ SET AUTOCOMMIT = 1;
BEGIN;
UPDATE t SET f = 'yellow 2' WHERE i = 3;
Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
SET AUTOCOMMIT = 1;
BEGIN;
UPDATE t SET f = 'magenta 2' WHERE f = 'red';
......@@ -51,7 +51,7 @@ SET AUTOCOMMIT = 1;
BEGIN;
UPDATE t SET f = 'gray 2' WHERE i = 3;
Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
SET AUTOCOMMIT = 1;
BEGIN;
UPDATE t SET f = 'dark blue 2' WHERE f = 'red';
......@@ -77,7 +77,7 @@ master-bin.000001 # Xid # # COMMIT /* XID */
SET AUTOCOMMIT = 0;
UPDATE t SET f = 'yellow 1' WHERE i = 3;
Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
SET AUTOCOMMIT = 0;
UPDATE t SET f = 'magenta 1' WHERE f = 'red';
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
......@@ -104,7 +104,7 @@ master-bin.000001 # Query # # ROLLBACK
SET AUTOCOMMIT = 0;
UPDATE t SET f = 'gray 1' WHERE i = 3;
Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
SET AUTOCOMMIT = 0;
UPDATE t SET f = 'dark blue 1' WHERE f = 'red';
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
......
......@@ -35,12 +35,9 @@ Got one of the listed errors
BEGIN;
Got one of the listed errors
Got one of the listed errors
Got one of the listed errors
BEGIN;
Got one of the listed errors
Got one of the listed errors
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
START SLAVE SQL_THREAD;
source include/diff_master_slave.inc;
########################################################################################
# 3 - BEGIN - COMMIT
......@@ -129,8 +126,6 @@ DROP TABLE t1;
DROP TABLE t2;
DROP TABLE t3;
DROP TABLE IF EXISTS t4;
Warnings:
Note 1051 Unknown table 't4'
DROP TABLE IF EXISTS t5;
DROP TABLE IF EXISTS t6;
Warnings:
......
......@@ -393,10 +393,8 @@ CREATE TEMPORARY TABLE tt_xx (a int);
-b-b-b-b-b-b-b-b-b-b-b- >> << -b-b-b-b-b-b-b-b-b-b-b-
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tt_xx (a int)
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO tt_1(ddl_case) VALUES (11)
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tt_xx (a int)
master-bin.000001 # Xid # # COMMIT /* XID */
-e-e-e-e-e-e-e-e-e-e-e- >> << -e-e-e-e-e-e-e-e-e-e-e-
......
......@@ -55,6 +55,7 @@ DROP TEMPORARY TABLE mysqltest1.tmp;
ROLLBACK;
SHOW CREATE TABLE mysqltest1.tmp;
ERROR 42S02: Table 'mysqltest1.tmp' doesn't exist
######### Must return no rows here #########
SELECT COUNT(*) FROM mysqltest1.t1;
COUNT(*)
0
......@@ -66,6 +67,7 @@ Table Create Table
tmp2 CREATE TEMPORARY TABLE `tmp2` (
`a` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
######### Must return no rows here #########
SELECT COUNT(*) FROM mysqltest1.t1;
COUNT(*)
0
......@@ -74,9 +76,10 @@ SHOW CREATE TABLE mysqltest1.tmp;
ERROR 42S02: Table 'mysqltest1.tmp' doesn't exist
SHOW CREATE TABLE mysqltest1.tmp2;
ERROR 42S02: Table 'mysqltest1.tmp2' doesn't exist
######### t1 has two rows here: the transaction not rolled back since t1 uses MyISAM #########
SELECT COUNT(*) FROM mysqltest1.t1;
COUNT(*)
0
2
FLUSH LOGS;
-------- switch to master --------
FLUSH LOGS;
......
......@@ -46,7 +46,9 @@ Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 107 Server ver: VERSION, Binlog ver: 4
master-bin.000001 107 Query 1 193 use `test`; CREATE TABLE t1 (a int)
master-bin.000001 193 Query 1 279 use `test`; CREATE TABLE t2 (a int)
master-bin.000001 279 Query 1 383 use `test`; DROP TABLE `t1` /* generated by server */
master-bin.000001 279 Query 1 403 use `test`; DROP TEMPORARY TABLE IF EXISTS `t2` /* generated by server */
master-bin.000001 403 Query 1 507 use `test`; DROP TABLE `t1` /* generated by server */
master-bin.000001 507 Query 1 631 use `test`; DROP TEMPORARY TABLE IF EXISTS `t2` /* generated by server */
SHOW TABLES;
Tables_in_test
t2
......
......@@ -466,6 +466,7 @@ Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.tt_1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `new_tt_xx` /* generated by server */
master-bin.000001 # Xid # # COMMIT /* XID */
-e-e-e-e-e-e-e-e-e-e-e- >> << -e-e-e-e-e-e-e-e-e-e-e-
......
......@@ -39,8 +39,6 @@ Got one of the listed errors
Got one of the listed errors
Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Non-transactional reads or writes are unsafe if they occur after transactional reads or writes inside a transaction.
Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional and non-transactional tables and write to any of them are unsafe.
BEGIN;
Got one of the listed errors
Got one of the listed errors
......
......@@ -393,10 +393,8 @@ CREATE TEMPORARY TABLE tt_xx (a int);
-b-b-b-b-b-b-b-b-b-b-b- >> << -b-b-b-b-b-b-b-b-b-b-b-
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tt_xx (a int)
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO tt_1(ddl_case) VALUES (11)
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tt_xx (a int)
master-bin.000001 # Xid # # COMMIT /* XID */
-e-e-e-e-e-e-e-e-e-e-e- >> << -e-e-e-e-e-e-e-e-e-e-e-
......@@ -431,10 +429,8 @@ DROP TEMPORARY TABLE IF EXISTS new_tt_xx;
-b-b-b-b-b-b-b-b-b-b-b- >> << -b-b-b-b-b-b-b-b-b-b-b-
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS new_tt_xx
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO tt_1(ddl_case) VALUES (8)
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS new_tt_xx
master-bin.000001 # Xid # # COMMIT /* XID */
-e-e-e-e-e-e-e-e-e-e-e- >> << -e-e-e-e-e-e-e-e-e-e-e-
......
......@@ -55,6 +55,7 @@ DROP TEMPORARY TABLE mysqltest1.tmp;
ROLLBACK;
SHOW CREATE TABLE mysqltest1.tmp;
ERROR 42S02: Table 'mysqltest1.tmp' doesn't exist
######### Must return no rows here #########
SELECT COUNT(*) FROM mysqltest1.t1;
COUNT(*)
0
......@@ -66,6 +67,7 @@ Table Create Table
tmp2 CREATE TEMPORARY TABLE `tmp2` (
`a` int(11) DEFAULT NULL
) ENGINE=MyISAM DEFAULT CHARSET=latin1
######### Must return no rows here #########
SELECT COUNT(*) FROM mysqltest1.t1;
COUNT(*)
0
......@@ -74,6 +76,7 @@ SHOW CREATE TABLE mysqltest1.tmp;
ERROR 42S02: Table 'mysqltest1.tmp' doesn't exist
SHOW CREATE TABLE mysqltest1.tmp2;
ERROR 42S02: Table 'mysqltest1.tmp2' doesn't exist
######### t1 has two rows here: the transaction not rolled back since t1 uses MyISAM #########
SELECT COUNT(*) FROM mysqltest1.t1;
COUNT(*)
2
......
......@@ -53,7 +53,7 @@ set @@global.debug="+d,stop_slave_middle_group";
set @@global.debug="+d,incomplete_group_in_relay_log";
update tm as t1, ti as t2 set t1.a=t1.a * 2, t2.a=t2.a * 2;
Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional and non-transactional tables and write to any of them are unsafe.
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
SELECT "Fatal error: ... The slave SQL is stopped, leaving the current group of events unfinished with a non-transaction table changed. If the group consists solely of Row-based events, you can try restarting the slave with --slave-exec-mode=IDEMPOTENT, which ignores duplicate key, key not found, and similar errors (see documentation for details)." AS Last_SQL_Error, @check as `true`;
Last_SQL_Error true
Fatal error: ... The slave SQL is stopped, leaving the current group of events unfinished with a non-transaction table changed. If the group consists solely of Row-based events, you can try restarting the slave with --slave-exec-mode=IDEMPOTENT, which ignores duplicate key, key not found, and similar errors (see documentation for details). 1
......
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
CALL mtr.add_suppression("Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT");
########################################################################
# VERIFY ITEMS 1 and 2
########################################################################
#
# Create temporary tables to verify when statements involving temporary
# tables are classified as safe or unsafe by printing out the warning
# messages.
#
CREATE TABLE t_myisam(id int) engine= MyIsam;
INSERT INTO t_myisam VALUES(1);
CREATE TABLE t_innodb(id int) engine= Innodb;
INSERT INTO t_innodb VALUES(1);
CREATE TEMPORARY TABLE t_myisam_temp(id int) engine= MyIsam;
INSERT INTO t_myisam_temp VALUES(1);
CREATE TEMPORARY TABLE t_innodb_temp(id int) engine= Innodb;
INSERT INTO t_innodb_temp VALUES(1);
BEGIN;
INSERT INTO t_myisam SELECT * FROM t_myisam_temp;
Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
INSERT INTO t_innodb SELECT * FROM t_myisam_temp;
INSERT INTO t_innodb SELECT * FROM t_innodb_temp;
ROLLBACK;
Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
BEGIN;
INSERT INTO t_myisam SELECT * FROM t_innodb_temp;
Warnings:
Note 1592 Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT. Reason for unsafeness: Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe.
INSERT INTO t_innodb SELECT * FROM t_myisam_temp;
INSERT INTO t_innodb SELECT * FROM t_innodb_temp;
ROLLBACK;
Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
########################################################################
# VERIFY ITEM 3
########################################################################
#
# When there is a temporary table we can switch between the mixed and
# row formats. However, we cannot switch to the statement format.
#
SET BINLOG_FORMAT=MIXED;
SET BINLOG_FORMAT=ROW;
SET BINLOG_FORMAT=MIXED;
SET BINLOG_FORMAT=STATEMENT;
ERROR HY000: Cannot switch out of the row-based binary log format when the session has open temporary tables
#
# When there is a temporary table we can switch between the mixed and
# row formats. However, we cannot swith to the statement format.
#
SET BINLOG_FORMAT=MIXED;
DROP TABLE t_myisam_temp, t_innodb_temp, t_myisam, t_innodb;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO t_myisam SELECT * FROM t_myisam_temp
master-bin.000001 # Query # # use `test`; INSERT INTO t_innodb SELECT * FROM t_myisam_temp
master-bin.000001 # Query # # use `test`; INSERT INTO t_innodb SELECT * FROM t_innodb_temp
master-bin.000001 # Query # # ROLLBACK
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO t_myisam SELECT * FROM t_innodb_temp
master-bin.000001 # Query # # use `test`; INSERT INTO t_innodb SELECT * FROM t_myisam_temp
master-bin.000001 # Query # # use `test`; INSERT INTO t_innodb SELECT * FROM t_innodb_temp
master-bin.000001 # Query # # ROLLBACK
master-bin.000001 # Query # # use `test`; DROP TABLE `t_myisam`,`t_innodb` /* generated by server */
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `t_myisam_temp`,`t_innodb_temp` /* generated by server */
########################################################################
# VERIFY ITEMS 4 and 5
########################################################################
#
BEGIN;
CREATE TEMPORARY TABLE tmp1(id int) engine= MyIsam;
INSERT INTO tmp1 VALUES(1);
CREATE TEMPORARY TABLE tmp2 LIKE tmp1;
INSERT INTO tmp2 VALUES(1);
CREATE TEMPORARY TABLE tmp3 engine= MyIsam SELECT * FROM tmp1;
INSERT INTO tmp3 VALUES(1);
DROP TEMPORARY TABLE tmp1;
DROP TEMPORARY TABLE tmp2;
DROP TEMPORARY TABLE tmp3;
COMMIT;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tmp1(id int) engine= MyIsam
master-bin.000001 # Query # # use `test`; INSERT INTO tmp1 VALUES(1)
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tmp2 LIKE tmp1
master-bin.000001 # Query # # use `test`; INSERT INTO tmp2 VALUES(1)
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tmp3 engine= MyIsam SELECT * FROM tmp1
master-bin.000001 # Query # # use `test`; INSERT INTO tmp3 VALUES(1)
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE tmp1
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE tmp2
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE tmp3
master-bin.000001 # Query # # COMMIT
BEGIN;
CREATE TEMPORARY TABLE tmp1(id int) engine= MyIsam;
INSERT INTO tmp1 VALUES(1);
CREATE TEMPORARY TABLE tmp2 LIKE tmp1;
INSERT INTO tmp2 VALUES(1);
CREATE TEMPORARY TABLE tmp3 engine= MyIsam SELECT * FROM tmp1;
INSERT INTO tmp3 VALUES(1);
DROP TEMPORARY TABLE tmp1;
DROP TEMPORARY TABLE tmp2;
DROP TEMPORARY TABLE tmp3;
ROLLBACK;
Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tmp1(id int) engine= MyIsam
master-bin.000001 # Query # # use `test`; INSERT INTO tmp1 VALUES(1)
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tmp2 LIKE tmp1
master-bin.000001 # Query # # use `test`; INSERT INTO tmp2 VALUES(1)
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tmp3 engine= MyIsam SELECT * FROM tmp1
master-bin.000001 # Query # # use `test`; INSERT INTO tmp3 VALUES(1)
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE tmp1
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE tmp2
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE tmp3
master-bin.000001 # Query # # ROLLBACK
########################################################################
# VERIFY ITEM 6
########################################################################
SET BINLOG_FORMAT=STATEMENT;
CREATE TEMPORARY TABLE tmp1(id int) engine= MyIsam;
CREATE TEMPORARY TABLE tmp2 LIKE tmp1;
CREATE TEMPORARY TABLE tmp3 engine= MyIsam SELECT * FROM tmp1;
SET BINLOG_FORMAT=ROW;
DROP TEMPORARY TABLE tmp1;
BEGIN;
INSERT INTO tmp2 VALUES(1);
DROP TEMPORARY TABLE tmp2;
INSERT INTO tmp3 VALUES(1);
DROP TEMPORARY TABLE tmp3;
COMMIT;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tmp1(id int) engine= MyIsam
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tmp2 LIKE tmp1
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tmp3 engine= MyIsam SELECT * FROM tmp1
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `tmp1` /* generated by server */
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `tmp2` /* generated by server */
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `tmp3` /* generated by server */
master-bin.000001 # Query # # COMMIT
SET BINLOG_FORMAT=STATEMENT;
CREATE TEMPORARY TABLE tmp1(id int) engine= MyIsam;
CREATE TEMPORARY TABLE tmp2 LIKE tmp1;
CREATE TEMPORARY TABLE tmp3 engine= MyIsam SELECT * FROM tmp1;
SET BINLOG_FORMAT=ROW;
DROP TEMPORARY TABLE tmp1;
BEGIN;
INSERT INTO tmp2 VALUES(1);
DROP TEMPORARY TABLE tmp2;
INSERT INTO tmp3 VALUES(1);
DROP TEMPORARY TABLE tmp3;
ROLLBACK;
Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tmp1(id int) engine= MyIsam
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tmp2 LIKE tmp1
master-bin.000001 # Query # # use `test`; CREATE TEMPORARY TABLE tmp3 engine= MyIsam SELECT * FROM tmp1
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `tmp1` /* generated by server */
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `tmp2` /* generated by server */
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `tmp3` /* generated by server */
master-bin.000001 # Query # # ROLLBACK
###################################################################################
# CHECK CONSISTENCY
###################################################################################
......@@ -12,14 +12,22 @@ source include/master-slave.inc;
sync_slave_with_master;
connection master;
--disable_query_log
CALL mtr.add_suppression("Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT");
--enable_query_log
create table t2(n int);
create temporary table t1 (n int);
insert into t1 values(1),(2),(3);
--disable_warnings
insert into t2 select * from t1;
--enable_warnings
connection master1;
create temporary table t1 (n int);
insert into t1 values (4),(5);
--disable_warnings
insert into t2 select * from t1 as t10;
--enable_warnings
save_master_pos;
disconnect master;
connection slave;
......
......@@ -94,7 +94,9 @@ select * from t1 into outfile "../../tmp/t1_slave.txt";
# Load data from slave into temp table on master
connection master;
--disable_warnings
create temporary table t1_slave select * from t1 where 1=0;
--enable_warnings
load data infile '../../tmp/t1_slave.txt' into table t1_slave;
--remove_file $MYSQLTEST_VARDIR/tmp/t1_slave.txt
......
......@@ -4,18 +4,25 @@
-- source include/have_binlog_format_mixed_or_statement.inc
-- source include/master-slave.inc
--disable_query_log
CALL mtr.add_suppression("Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT");
--enable_query_log
create table t2 (n int, PRIMARY KEY(n));
create temporary table t1 (n int);
create temporary table t3 (n int not null);
insert into t1 values(1),(2),(3),(100),(25),(26),(200),(300);
--disable_warnings
insert into t2 select * from t1;
--enable_warnings
alter table t3 add primary key(n);
flush logs;
insert into t3 values (1010);
--disable_warnings
insert into t2 select * from t3;
--enable_warnings
drop table if exists t3;
insert into t2 values (1012);
......@@ -23,7 +30,9 @@ insert into t2 values (1012);
connection master1;
create temporary table t1 (n int);
insert into t1 values (4),(5);
--disable_warnings
insert into t2 select * from t1;
--enable_warnings
save_master_pos;
disconnect master;
......
################################################################################
# BUG#51894 Replication failure with SBR on DROP TEMPORARY TABLE inside a
# transaction
# BUG#52616 Temp table prevents switch binlog format from STATEMENT to ROW
#
# This test verifies what follows:
#
# 1 - If the following statements are classified as unsafe:
# 1.1 - INSERT INTO t_myisam SELECT * FROM t_myisam_temp
# 1.2 - INSERT INTO t_myisam_temp SELECT * FROM t_myisam
#
# 2 - If the following statements are classified as safe:
# 1.7 - INSERT INTO t_innodb SELECT * FROM t_myisam_temp
# 1.8 - INSERT INTO t_myisam_temp SELECT * FROM t_innodb
#
# 3 - If we can switch from statement to row format.
#
# 4 - If statements that can manipulate a temporary table and do not cause an
# implicit commit are kept in the boundaries of an on-going transaction. For
# instance:
# 4.1 - CREATE TEMPORARY TABLE
# 4.2 - CREATE TEMPORARY TABLE LIKE
# 4.3 - CREATE TEMPORARY TABLE SELECT * FROM
# 4.4 - INSERT/UPDATE/DELETE (Note that only inserts are verified)
# 4.5 - INSERT INTO t_myisam SELECT * FROM t_myisam_temp
# 4.6 - INSERT INTO t_myisam_temp SELECT * FROM t_myisam
# 4.7 - INSERT INTO t_innodb SELECT * FROM t_myisam_temp
# 4.8 - INSERT INTO t_myisam_temp SELECT * FROM t_innodb
#
# 5 - If transactions that have a DROP TEMPORARY are always written to the
# binary log regardless of the mode and the outcome: commit or rollback.
#
# 6 - In particular, if the current statement logging format is set to row
# the CREATE TEMPORARY is not logged and the DROP TEMPORARY is extended with
# the IF EXISTS clause.
#
################################################################################
source include/master-slave.inc;
source include/have_binlog_format_statement.inc;
source include/have_innodb.inc;
CALL mtr.add_suppression("Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT");
--echo ########################################################################
--echo # VERIFY ITEMS 1 and 2
--echo ########################################################################
--echo #
--echo # Create temporary tables to verify when statements involving temporary
--echo # tables are classified as safe or unsafe by printing out the warning
--echo # messages.
--echo #
connection master;
CREATE TABLE t_myisam(id int) engine= MyIsam;
INSERT INTO t_myisam VALUES(1);
CREATE TABLE t_innodb(id int) engine= Innodb;
INSERT INTO t_innodb VALUES(1);
CREATE TEMPORARY TABLE t_myisam_temp(id int) engine= MyIsam;
INSERT INTO t_myisam_temp VALUES(1);
CREATE TEMPORARY TABLE t_innodb_temp(id int) engine= Innodb;
INSERT INTO t_innodb_temp VALUES(1);
let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1);
BEGIN;
INSERT INTO t_myisam SELECT * FROM t_myisam_temp;
INSERT INTO t_innodb SELECT * FROM t_myisam_temp;
INSERT INTO t_innodb SELECT * FROM t_innodb_temp;
ROLLBACK;
BEGIN;
INSERT INTO t_myisam SELECT * FROM t_innodb_temp;
INSERT INTO t_innodb SELECT * FROM t_myisam_temp;
INSERT INTO t_innodb SELECT * FROM t_innodb_temp;
ROLLBACK;
--echo ########################################################################
--echo # VERIFY ITEM 3
--echo ########################################################################
--echo #
--echo # When there is a temporary table we can switch between the mixed and
--echo # row formats. However, we cannot switch to the statement format.
--echo #
SET BINLOG_FORMAT=MIXED;
SET BINLOG_FORMAT=ROW;
SET BINLOG_FORMAT=MIXED;
--error ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR
SET BINLOG_FORMAT=STATEMENT;
--echo #
--echo # When there is a temporary table we can switch between the mixed and
--echo # row formats. However, we cannot swith to the statement format.
--echo #
SET BINLOG_FORMAT=MIXED;
DROP TABLE t_myisam_temp, t_innodb_temp, t_myisam, t_innodb;
source include/show_binlog_events.inc;
--echo ########################################################################
--echo # VERIFY ITEMS 4 and 5
--echo ########################################################################
--echo #
let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1);
BEGIN;
CREATE TEMPORARY TABLE tmp1(id int) engine= MyIsam;
INSERT INTO tmp1 VALUES(1);
CREATE TEMPORARY TABLE tmp2 LIKE tmp1;
INSERT INTO tmp2 VALUES(1);
CREATE TEMPORARY TABLE tmp3 engine= MyIsam SELECT * FROM tmp1;
INSERT INTO tmp3 VALUES(1);
DROP TEMPORARY TABLE tmp1;
DROP TEMPORARY TABLE tmp2;
DROP TEMPORARY TABLE tmp3;
COMMIT;
source include/show_binlog_events.inc;
let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1);
BEGIN;
CREATE TEMPORARY TABLE tmp1(id int) engine= MyIsam;
INSERT INTO tmp1 VALUES(1);
CREATE TEMPORARY TABLE tmp2 LIKE tmp1;
INSERT INTO tmp2 VALUES(1);
CREATE TEMPORARY TABLE tmp3 engine= MyIsam SELECT * FROM tmp1;
INSERT INTO tmp3 VALUES(1);
DROP TEMPORARY TABLE tmp1;
DROP TEMPORARY TABLE tmp2;
DROP TEMPORARY TABLE tmp3;
ROLLBACK;
source include/show_binlog_events.inc;
--echo ########################################################################
--echo # VERIFY ITEM 6
--echo ########################################################################
SET BINLOG_FORMAT=STATEMENT;
let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1);
CREATE TEMPORARY TABLE tmp1(id int) engine= MyIsam;
CREATE TEMPORARY TABLE tmp2 LIKE tmp1;
CREATE TEMPORARY TABLE tmp3 engine= MyIsam SELECT * FROM tmp1;
SET BINLOG_FORMAT=ROW;
DROP TEMPORARY TABLE tmp1;
BEGIN;
INSERT INTO tmp2 VALUES(1);
DROP TEMPORARY TABLE tmp2;
INSERT INTO tmp3 VALUES(1);
DROP TEMPORARY TABLE tmp3;
COMMIT;
source include/show_binlog_events.inc;
SET BINLOG_FORMAT=STATEMENT;
let $binlog_start= query_get_value("SHOW MASTER STATUS", Position, 1);
CREATE TEMPORARY TABLE tmp1(id int) engine= MyIsam;
CREATE TEMPORARY TABLE tmp2 LIKE tmp1;
CREATE TEMPORARY TABLE tmp3 engine= MyIsam SELECT * FROM tmp1;
SET BINLOG_FORMAT=ROW;
DROP TEMPORARY TABLE tmp1;
BEGIN;
INSERT INTO tmp2 VALUES(1);
DROP TEMPORARY TABLE tmp2;
INSERT INTO tmp3 VALUES(1);
DROP TEMPORARY TABLE tmp3;
ROLLBACK;
source include/show_binlog_events.inc;
--echo ###################################################################################
--echo # CHECK CONSISTENCY
--echo ###################################################################################
connection master;
sync_slave_with_master;
--exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/test-nmt-master.sql
--exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert --no-create-info test > $MYSQLTEST_VARDIR/tmp/test-nmt-slave.sql
--diff_files $MYSQLTEST_VARDIR/tmp/test-nmt-master.sql $MYSQLTEST_VARDIR/tmp/test-nmt-slave.sql
......@@ -51,6 +51,10 @@ reset master;
connection master;
--disable_query_log
CALL mtr.add_suppression("Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT");
--enable_query_log
disable_warnings;
DROP TABLE IF EXISTS t1;
enable_warnings;
......@@ -137,7 +141,9 @@ SELECT COUNT(*) FROM t1;
connection con1;
create temporary table t3(f int);
--disable_warnings
insert into t3 select * from t1 where f<6;
--enable_warnings
let $wait_condition= SELECT COUNT(*) = 5 FROM t3;
--source include/wait_condition.inc
......@@ -145,12 +151,16 @@ connection con2;
create temporary table t3(f int);
connection con1;
--disable_warnings
insert into t2 select count(*) from t3;
--enable_warnings
let $wait_condition= SELECT COUNT(*) = 1 FROM t2;
--source include/wait_condition.inc
connection con2;
--disable_warnings
insert into t3 select * from t1 where f>=4;
--enable_warnings
let $wait_condition= SELECT COUNT(*) = 7 FROM t3;
--source include/wait_condition.inc
......@@ -158,7 +168,9 @@ connection con1;
drop temporary table t3;
connection con2;
--disable_warnings
insert into t2 select count(*) from t3;
--enable_warnings
drop temporary table t3;
select * from t2 ORDER BY f;
......@@ -183,22 +195,30 @@ SET @@session.pseudo_thread_id=1;
create temporary table t3(f int);
SET TIMESTAMP=1040323952;
SET @@session.pseudo_thread_id=1;
--disable_warnings
insert into t3 select * from t1 where f<6;
--enable_warnings
SET TIMESTAMP=1040324145;
SET @@session.pseudo_thread_id=2;
create temporary table t3(f int);
SET TIMESTAMP=1040324186;
SET @@session.pseudo_thread_id=1;
--disable_warnings
insert into t2 select count(*) from t3;
--enable_warnings
SET TIMESTAMP=1040324200;
SET @@session.pseudo_thread_id=2;
--disable_warnings
insert into t3 select * from t1 where f>=4;
--enable_warnings
SET TIMESTAMP=1040324211;
SET @@session.pseudo_thread_id=1;
drop temporary table t3;
SET TIMESTAMP=1040324219;
SET @@session.pseudo_thread_id=2;
--disable_warnings
insert into t2 select count(*) from t3;
--enable_warnings
SET TIMESTAMP=1040324224;
SET @@session.pseudo_thread_id=2;
drop temporary table t3;
......@@ -226,7 +246,9 @@ sync_slave_with_master;
# connection slave
stop slave; # to prepare for reconnecting w/o waiting for timeout
connection master;
--disable_warnings
insert into t5 select * from t4;
--enable_warnings
save_master_pos;
connection slave;
......
......@@ -532,6 +532,9 @@ DROP TEMPORARY TABLE IF EXISTS new_tt_xx;
-b-b-b-b-b-b-b-b-b-b-b- >> << -b-b-b-b-b-b-b-b-b-b-b-
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; DROP TEMPORARY TABLE IF EXISTS `new_tt_xx` /* generated by server */
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.tt_1)
master-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status)
master-bin.000001 # Write_rows # # table_id: #
......
......@@ -27,18 +27,17 @@ SELECT * FROM t1 ORDER BY a,b;
a b
**** On Master ****
DROP TABLE t1;
SHOW BINLOG EVENTS;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 107 Server ver: SERVER_VERSION, Binlog ver: 4
master-bin.000001 107 Query 1 224 use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB
master-bin.000001 224 Query 1 288 BEGIN
master-bin.000001 288 Table_map 1 331 table_id: # (test.t1)
master-bin.000001 331 Table_map 1 393 table_id: # (mysql.ndb_apply_status)
master-bin.000001 393 Write_rows 1 452 table_id: #
master-bin.000001 452 Write_rows 1 499 table_id: # flags: STMT_END_F
master-bin.000001 499 Query 1 564 COMMIT
master-bin.000001 564 Query 1 644 use `test`; TRUNCATE TABLE t1
master-bin.000001 644 Query 1 720 use `test`; DROP TABLE t1
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status)
master-bin.000001 # Write_rows # # table_id: #
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1
master-bin.000001 # Query # # use `test`; DROP TABLE t1
**** On Master ****
CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB;
INSERT INTO t1 VALUES (1,1), (2,2);
......@@ -63,29 +62,28 @@ a b
3 3
**** On Master ****
DROP TABLE t1;
SHOW BINLOG EVENTS;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 107 Server ver: SERVER_VERSION, Binlog ver: 4
master-bin.000001 107 Query 1 224 use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB
master-bin.000001 224 Query 1 288 BEGIN
master-bin.000001 288 Table_map 1 331 table_id: # (test.t1)
master-bin.000001 331 Table_map 1 393 table_id: # (mysql.ndb_apply_status)
master-bin.000001 393 Write_rows 1 452 table_id: #
master-bin.000001 452 Write_rows 1 499 table_id: # flags: STMT_END_F
master-bin.000001 499 Query 1 564 COMMIT
master-bin.000001 564 Query 1 644 use `test`; TRUNCATE TABLE t1
master-bin.000001 644 Query 1 720 use `test`; DROP TABLE t1
master-bin.000001 720 Query 1 837 use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB
master-bin.000001 837 Query 1 901 BEGIN
master-bin.000001 901 Table_map 1 944 table_id: # (test.t1)
master-bin.000001 944 Table_map 1 1006 table_id: # (mysql.ndb_apply_status)
master-bin.000001 1006 Write_rows 1 1065 table_id: #
master-bin.000001 1065 Write_rows 1 1112 table_id: # flags: STMT_END_F
master-bin.000001 1112 Query 1 1177 COMMIT
master-bin.000001 1177 Query 1 1241 BEGIN
master-bin.000001 1241 Table_map 1 1284 table_id: # (test.t1)
master-bin.000001 1284 Table_map 1 1346 table_id: # (mysql.ndb_apply_status)
master-bin.000001 1346 Write_rows 1 1405 table_id: #
master-bin.000001 1405 Delete_rows 1 1444 table_id: # flags: STMT_END_F
master-bin.000001 1444 Query 1 1509 COMMIT
master-bin.000001 1509 Query 1 1585 use `test`; DROP TABLE t1
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status)
master-bin.000001 # Write_rows # # table_id: #
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; TRUNCATE TABLE t1
master-bin.000001 # Query # # use `test`; DROP TABLE t1
master-bin.000001 # Query # # use `test`; CREATE TABLE t1 (a INT PRIMARY KEY, b LONG) ENGINE=NDB
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status)
master-bin.000001 # Write_rows # # table_id: #
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status)
master-bin.000001 # Write_rows # # table_id: #
master-bin.000001 # Delete_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; DROP TABLE t1
......@@ -39,10 +39,7 @@ SELECT * FROM t1 ORDER BY a,b;
--echo **** On Master ****
connection master;
DROP TABLE t1;
let SERVER_VERSION=`select version()`;
--replace_regex /\/\* xid=[0-9]+ \*\//\/* xid= *\// /table_id: [0-9]+/table_id: #/
--replace_result $SERVER_VERSION SERVER_VERSION
SHOW BINLOG EVENTS;
--source include/show_binlog_events.inc
--echo **** On Master ****
connection master;
......@@ -64,8 +61,6 @@ SELECT * FROM t1 ORDER BY a,b;
--echo **** On Master ****
connection master;
DROP TABLE t1;
--replace_regex /table_id: [0-9]+/table_id: #/
--replace_result $SERVER_VERSION SERVER_VERSION
SHOW BINLOG EVENTS;
--source include/show_binlog_events.inc
-- source include/master-slave-end.inc
......@@ -8,6 +8,10 @@
# This does not work for RBR yet.
--source include/have_binlog_format_mixed_or_statement.inc
--disable_query_log
CALL mtr.add_suppression("Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT");
--enable_query_log
-- source include/have_innodb.inc
--disable_warnings
drop table if exists t1, t2;
......
......@@ -5,6 +5,9 @@
-- source extra/binlog_tests/ctype_cp932_binlog.test
call mtr.add_suppression('Error in Log_event::read_log_event()');
--disable_query_log
CALL mtr.add_suppression("Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT");
--enable_query_log
#
# Bug#18293: Values in stored procedure written to binlog unescaped
......@@ -79,9 +82,11 @@ ORDER BY head, tail;
#
# Populate t1 with Half Width Kana [A1..DF]
#
--disable_warnings
INSERT t1 (code) SELECT head FROM head
WHERE (head BETWEEN 'A1' AND 'DF')
ORDER BY head;
--enable_warnings
DROP TEMPORARY TABLE head, tail;
SHOW CREATE TABLE t1;
UPDATE t1 SET a=unhex(code) ORDER BY code;
......
......@@ -4,6 +4,10 @@
-- source include/have_log_bin.inc
--disable_query_log
CALL mtr.add_suppression("Unsafe statement binlogged in statement format since BINLOG_FORMAT = STATEMENT");
--enable_query_log
# Deletes all the binary logs
reset master;
......
......@@ -1576,7 +1576,7 @@ binlog_truncate_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr, bool all)
inside a transaction, we reset the transaction cache.
*/
thd->binlog_remove_pending_rows_event(TRUE, is_transactional);
if (all || !thd->in_multi_stmt_transaction())
if (ending_trans(thd, all))
{
if (cache_mngr->trx_cache.has_incident())
error= mysql_bin_log.write_incident(thd, TRUE);
......@@ -1682,12 +1682,11 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
DBUG_ENTER("binlog_commit");
binlog_cache_mngr *const cache_mngr=
(binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
bool const in_transaction= thd->in_multi_stmt_transaction();
DBUG_PRINT("debug",
("all: %d, in_transaction: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s",
all,
YESNO(in_transaction),
YESNO(thd->in_multi_stmt_transaction()),
YESNO(thd->transaction.all.modified_non_trans_table),
YESNO(thd->transaction.stmt.modified_non_trans_table)));
......@@ -1711,7 +1710,7 @@ static int binlog_commit(handlerton *hton, THD *thd, bool all)
- We are in a transaction and a full transaction is committed.
Otherwise, we accumulate the changes.
*/
if (!in_transaction || all)
if (ending_trans(thd, all))
{
Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE, TRUE, 0);
error= binlog_flush_trx_cache(thd, cache_mngr, &qev);
......@@ -1789,29 +1788,28 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
{
/*
We flush the cache wrapped in a beging/rollback if:
. aborting a transcation that modified a non-transactional table or;
. aborting a statement that modified both transactional and
non-transctional tables but which is not in the boundaries of any
transaction;
. aborting a single or multi-statement transaction and;
. the format is STMT and non-trans engines were updated or;
. the OPTION_KEEP_LOG is activate.
*/
if (thd->variables.binlog_format == BINLOG_FORMAT_STMT &&
((all && thd->transaction.all.modified_non_trans_table) ||
(!all && thd->transaction.stmt.modified_non_trans_table &&
!thd->in_multi_stmt_transaction()) ||
(thd->variables.option_bits & OPTION_KEEP_LOG)))
if (ending_trans(thd, all) &&
((thd->variables.option_bits & OPTION_KEEP_LOG) ||
(trans_has_updated_non_trans_table(thd) &&
thd->variables.binlog_format == BINLOG_FORMAT_STMT)))
{
Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE, TRUE, 0);
error= binlog_flush_trx_cache(thd, cache_mngr, &qev);
}
/*
Otherwise, we simply truncate the cache as there is no change on
non-transactional tables as follows.
Truncate the cache if:
. aborting a single or multi-statement transaction or;
. the OPTION_KEEP_LOG is not activate and;
. the format is not STMT or no non-trans were updated.
*/
else if (all || (!all &&
(!thd->transaction.stmt.modified_non_trans_table ||
!thd->in_multi_stmt_transaction() ||
thd->variables.binlog_format != BINLOG_FORMAT_STMT)))
else if (ending_trans(thd, all) ||
(!(thd->variables.option_bits & OPTION_KEEP_LOG) &&
((!stmt_has_updated_non_trans_table(thd) ||
thd->variables.binlog_format != BINLOG_FORMAT_STMT))))
error= binlog_truncate_trx_cache(thd, cache_mngr, all);
}
......@@ -1909,7 +1907,7 @@ static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
non-transactional table. Otherwise, truncate the binlog cache starting
from the SAVEPOINT command.
*/
if (unlikely(thd->transaction.all.modified_non_trans_table ||
if (unlikely(trans_has_updated_non_trans_table(thd) ||
(thd->variables.option_bits & OPTION_KEEP_LOG)))
{
int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
......@@ -4257,6 +4255,49 @@ bool use_trans_cache(const THD* thd, bool is_transactional)
(is_transactional || !cache_mngr->trx_cache.empty()));
}
/**
This function checks if a transaction, either a multi-statement
or a single statement transaction is about to commit or not.
@param thd The client thread that executed the current statement.
@param all Committing a transaction (i.e. TRUE) or a statement
(i.e. FALSE).
@return
@c true if committing a transaction, otherwise @c false.
*/
bool ending_trans(THD* thd, const bool all)
{
return (all || (!all && !thd->in_multi_stmt_transaction()));
}
/**
This function checks if a non-transactional table was updated by
the current transaction.
@param thd The client thread that executed the current statement.
@return
@c true if a non-transactional table was updated, @c false
otherwise.
*/
bool trans_has_updated_non_trans_table(const THD* thd)
{
return (thd->transaction.all.modified_non_trans_table ||
thd->transaction.stmt.modified_non_trans_table);
}
/**
This function checks if a non-transactional table was updated by the
current statement.
@param thd The client thread that executed the current statement.
@return
@c true if a non-transactional table was updated, @c false otherwise.
*/
bool stmt_has_updated_non_trans_table(const THD* thd)
{
return (thd->transaction.stmt.modified_non_trans_table);
}
/*
These functions are placed in this file since they need access to
binlog_hton, which has internal linkage.
......@@ -4539,7 +4580,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
{
set_write_error(thd);
if (check_write_error(thd) && cache_data &&
thd->transaction.stmt.modified_non_trans_table)
stmt_has_updated_non_trans_table(thd))
cache_data->set_incident();
DBUG_RETURN(1);
}
......@@ -4740,7 +4781,7 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
{
set_write_error(thd);
if (check_write_error(thd) && cache_data &&
thd->transaction.stmt.modified_non_trans_table)
stmt_has_updated_non_trans_table(thd))
cache_data->set_incident();
}
}
......
......@@ -26,6 +26,9 @@ class Format_description_log_event;
bool trans_has_updated_trans_table(const THD* thd);
bool stmt_has_updated_trans_table(const THD *thd);
bool use_trans_cache(const THD* thd, bool is_transactional);
bool ending_trans(THD* thd, const bool all);
bool trans_has_updated_non_trans_table(const THD* thd);
bool stmt_has_updated_non_trans_table(const THD* thd);
/*
Transaction Coordinator log - a base abstract class
......
......@@ -679,6 +679,7 @@ Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
server_id= thd->server_id;
when= thd->start_time;
cache_type= (using_trans || stmt_has_updated_trans_table(thd)
|| thd->thread_specific_used
? Log_event::EVENT_TRANSACTIONAL_CACHE :
Log_event::EVENT_STMT_CACHE);
}
......@@ -2470,6 +2471,7 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
*/
LEX *lex= thd->lex;
bool implicit_commit= FALSE;
bool force_trans= FALSE;
cache_type= Log_event::EVENT_INVALID_CACHE;
switch (lex->sql_command)
{
......@@ -2483,14 +2485,16 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
implicit_commit= TRUE;
break;
case SQLCOM_DROP_TABLE:
implicit_commit= !(lex->drop_temporary && thd->in_multi_stmt_transaction());
force_trans= lex->drop_temporary && thd->in_multi_stmt_transaction();
implicit_commit= !force_trans;
break;
case SQLCOM_ALTER_TABLE:
case SQLCOM_CREATE_TABLE:
implicit_commit= !((lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
thd->in_multi_stmt_transaction()) &&
!(lex->select_lex.item_list.elements &&
thd->is_current_stmt_binlog_format_row());
force_trans= (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE) &&
thd->in_multi_stmt_transaction();
implicit_commit= !force_trans &&
!(lex->select_lex.item_list.elements &&
thd->is_current_stmt_binlog_format_row());
break;
case SQLCOM_SET_OPTION:
implicit_commit= (lex->autocommit ? TRUE : FALSE);
......@@ -2548,7 +2552,8 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
}
else
{
cache_type= (using_trans || stmt_has_updated_trans_table(thd)
cache_type= ((using_trans || stmt_has_updated_trans_table(thd) ||
force_trans || thd->thread_specific_used)
? Log_event::EVENT_TRANSACTIONAL_CACHE :
Log_event::EVENT_STMT_CACHE);
}
......@@ -7733,12 +7738,6 @@ int Rows_log_event::do_apply_event(Relay_log_info const *rli)
clear_all_errors(thd, const_cast<Relay_log_info*>(rli));
error= 0;
}
if (!use_trans_cache())
{
DBUG_PRINT("info", ("Marked that we need to keep log"));
thd->variables.option_bits|= OPTION_KEEP_LOG;
}
} // if (table)
......
......@@ -241,11 +241,6 @@ Old_rows_log_event::do_apply_event(Old_rows_log_event *ev, const Relay_log_info
DBUG_EXECUTE_IF("stop_slave_middle_group",
const_cast<Relay_log_info*>(rli)->abort_slave= 1;);
error= do_after_row_operations(table, error);
if (!ev->use_trans_cache())
{
DBUG_PRINT("info", ("Marked that we need to keep log"));
ev_thd->variables.option_bits|= OPTION_KEEP_LOG;
}
}
if (error)
......@@ -1683,11 +1678,6 @@ int Old_rows_log_event::do_apply_event(Relay_log_info const *rli)
DBUG_EXECUTE_IF("stop_slave_middle_group",
const_cast<Relay_log_info*>(rli)->abort_slave= 1;);
error= do_after_row_operations(rli, error);
if (!use_trans_cache())
{
DBUG_PRINT("info", ("Marked that we need to keep log"));
thd->variables.option_bits|= OPTION_KEEP_LOG;
}
} // if (table)
if (error)
......
......@@ -6335,4 +6335,4 @@ ER_BINLOG_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE
eng "Mixing self-logging and non-self-logging engines in a statement is unsafe."
ER_BINLOG_UNSAFE_MIXED_STATEMENT
eng "Statements that read from both transactional and non-transactional tables and write to any of them are unsafe."
eng "Statements that read from both transactional (or a temporary table of any engine type) and non-transactional tables and write to any of them are unsafe."
......@@ -3661,19 +3661,80 @@ int THD::decide_logging_format(TABLE_LIST *tables)
if (prev_write_table && prev_write_table->file->ht !=
table->table->file->ht)
multi_write_engine= TRUE;
/*
Every temporary table must be always written to the binary
log in transaction boundaries and as such we artificially
classify them as transactional.
Indirectly, this avoids classifying a temporary table created
on a non-transactional engine as unsafe when it is modified
after any transactional table:
BEGIN;
INSERT INTO innodb_t VALUES (1);
INSERT INTO myisam_t_temp VALUES (1);
COMMIT;
BINARY LOG:
BEGIN;
INSERT INTO innodb_t VALUES (1);
INSERT INTO myisam_t_temp VALUES (1);
COMMIT;
*/
all_trans_write_engines= all_trans_write_engines &&
table->table->file->has_transactions();
(table->table->file->has_transactions() ||
table->table->s->tmp_table);
prev_write_table= table->table;
flags_write_all_set &= flags;
flags_write_some_set |= flags;
}
flags_some_set |= flags;
if (prev_access_table && prev_access_table->file->ht != table->table->file->ht)
/*
The mixture of non-transactional and transactional tables must
identified and classified as unsafe. However, a temporary table
must be always handled as a transactional table. Based on that,
we have the following statements classified as mixed and by
consequence as unsafe:
1: INSERT INTO myisam_t SELECT * FROM innodb_t;
2: INSERT INTO innodb_t SELECT * FROM myisam_t;
3: INSERT INTO myisam_t SELECT * FROM myisam_t_temp;
4: INSERT INTO myisam_t_temp SELECT * FROM myisam_t;
5: CREATE TEMPORARY TABLE myisam_t_temp SELECT * FROM mysiam_t;
The following statements are not considered mixed and as such
are safe:
1: INSERT INTO innodb_t SELECT * FROM myisam_t_temp;
2: INSERT INTO myisam_t_temp SELECT * FROM innodb_t_temp;
*/
if (!trans_non_trans_access_engines && prev_access_table &&
(lex->sql_command != SQLCOM_CREATE_TABLE ||
(lex->sql_command == SQLCOM_CREATE_TABLE &&
(lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))))
{
my_bool prev_trans;
my_bool act_trans;
if (prev_access_table->s->tmp_table || table->table->s->tmp_table)
{
prev_trans= prev_access_table->s->tmp_table ? TRUE :
prev_access_table->file->has_transactions();
act_trans= table->table->s->tmp_table ? TRUE :
table->table->file->has_transactions();
}
else
{
prev_trans= prev_access_table->file->has_transactions();
act_trans= table->table->file->has_transactions();
}
trans_non_trans_access_engines= (prev_trans != act_trans);
multi_access_engine= TRUE;
trans_non_trans_access_engines= trans_non_trans_access_engines ||
(prev_access_table->file->has_transactions() !=
table->table->file->has_transactions());
}
prev_access_table= table->table;
}
......@@ -3710,6 +3771,12 @@ int THD::decide_logging_format(TABLE_LIST *tables)
2: INSERT INTO innodb_t SELECT * FROM myisam_t;
3: INSERT INTO myisam_t SELECT * FROM myisam_t_temp;
4: INSERT INTO myisam_t_temp SELECT * FROM myisam_t;
5: CREATE TEMPORARY TABLE myisam_t_temp SELECT * FROM mysiam_t;
are classified as unsafe to ensure that in mixed mode the execution is
completely safe and equivalent to the row mode. Consider the following
statements and sessions (connections) to understand the reason:
......
......@@ -2531,11 +2531,11 @@ class THD :public Statement,
("temporary_tables: %s, in_sub_stmt: %s, system_thread: %s",
YESNO(temporary_tables), YESNO(in_sub_stmt),
show_system_thread(system_thread)));
if ((temporary_tables == NULL) && (in_sub_stmt == 0))
if (in_sub_stmt == 0)
{
if (variables.binlog_format == BINLOG_FORMAT_ROW)
set_current_stmt_binlog_format_row();
else
else if (temporary_tables == NULL)
clear_current_stmt_binlog_format_row();
}
DBUG_VOID_RETURN;
......
......@@ -1998,8 +1998,13 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
case 0:
// removed temporary table
tmp_table_deleted= 1;
if (thd->variables.binlog_format == BINLOG_FORMAT_MIXED &&
thd->is_current_stmt_binlog_format_row())
/*
One needs to always log any temporary table drop if the current
statement logging format is set to row. This happens because one
might have created a temporary table while the statement logging
format was statement and then switched to mixed or row format.
*/
if (thd->is_current_stmt_binlog_format_row())
{
if (built_tmp_query.is_empty())
{
......@@ -2191,7 +2196,7 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
deleted one or more non-temporary tables (and no temporary
tables). In this case, we can write the original query into
the binary log.
*/
*/
error |= write_bin_log(thd, !error, thd->query(), thd->query_length());
}
else if (thd->is_current_stmt_binlog_format_row() &&
......@@ -2218,11 +2223,12 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
}
/*
One needs to always log any temporary table drop, if:
1. thread logging format is mixed mode; AND
2. current statement logging format is set to row.
One needs to always log any temporary table drop if the current
statement logging format is set to row. This happens because one
might have created a temporary table while the statement logging
format was statement and then switched to mixed or row format.
*/
if (thd->variables.binlog_format == BINLOG_FORMAT_MIXED)
if (thd->is_current_stmt_binlog_format_row())
{
/*
In this case we have deleted some temporary tables but we are using
......@@ -2233,8 +2239,14 @@ int mysql_rm_table_part2(THD *thd, TABLE_LIST *tables, bool if_exists,
*/
built_tmp_query.chop(); // Chop of the last comma
built_tmp_query.append(" /* generated by server */");
error|= write_bin_log(thd, !error, built_tmp_query.ptr(), built_tmp_query.length(),
thd->in_multi_stmt_transaction());
/*
We cannot call the write_bin_log as we do not care about any errors
in the master as the statement is always DROP TEMPORARY TABLE IF EXISTS
and as such there will be no errors in the slave.
*/
error|= thd->binlog_query(THD::STMT_QUERY_TYPE, built_tmp_query.ptr(),
built_tmp_query.length(), FALSE, FALSE, FALSE,
0);
}
}
......@@ -3749,43 +3761,6 @@ void sp_prepare_create_field(THD *thd, Create_field *sql_field)
(void) prepare_blob_field(thd, sql_field);
}
/*
Write CREATE TABLE binlog
SYNOPSIS
write_create_table_bin_log()
thd Thread object
create_info Create information
internal_tmp_table Set to 1 if this is an internal temporary table
DESCRIPTION
This function only is called in mysql_create_table_no_lock and
mysql_create_table
RETURN VALUES
NONE
*/
static inline int write_create_table_bin_log(THD *thd,
const HA_CREATE_INFO *create_info,
bool internal_tmp_table)
{
/*
Don't write statement if:
- It is an internal temporary table,
- Row-based logging is used and it we are creating a temporary table, or
- The binary log is not open.
Otherwise, the statement shall be binlogged.
*/
if (!internal_tmp_table &&
(!thd->is_current_stmt_binlog_format_row() ||
(thd->is_current_stmt_binlog_format_row() &&
!(create_info->options & HA_LEX_CREATE_TMP_TABLE))))
return write_bin_log(thd, TRUE, thd->query(), thd->query_length());
return 0;
}
/*
Create a table
......
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