Commit e662b51e authored by Alfranio Correia's avatar Alfranio Correia

BUG#53259 Unsafe statement binlogged in statement format w/MyIsam temp tables

BUG#54872 MBR: replication failure caused by using tmp table inside transaction 
      
Changed criteria to classify a statement as unsafe in order to reduce the
number of spurious warnings. So a statement is classified as unsafe when
there is on-going transaction at any point of the execution if:

1. The mixed statement is about to update a transactional table and
a non-transactional table.

2. The mixed statement is about to update a temporary transactional
table and a non-transactional table.
      
3. The mixed statement is about to update a transactional table and
read from a non-transactional table.

4. The mixed statement is about to update a temporary transactional
table and read from a non-transactional table.

5. The mixed statement is about to update a non-transactional table
and read from a transactional table when the isolation level is
lower than repeatable read.

After updating a transactional table if:

6. The mixed statement is about to update a non-transactional table
and read from a temporary transactional table.
 
7. The mixed statement is about to update a non-transactional table
 and read from a temporary transactional table.

8. The mixed statement is about to update a non-transactionala table
   and read from a temporary non-transactional table.
     
9. The mixed statement is about to update a temporary non-transactional
table and update a non-transactional table.
     
10. The mixed statement is about to update a temporary non-transactional
table and read from a non-transactional table.
     
11. A statement is about to update a non-transactional table and the
option variables.binlog_direct_non_trans_update is OFF.

The reason for this is that locks acquired may not protected a concurrent
transaction of interfering in the current execution and by consequence in
the result. So the patch reduced the number of spurious unsafe warnings.

Besides we fixed a regression caused by BUG#51894, which makes temporary
tables to go into the trx-cache if there is an on-going transaction. In
MIXED mode, the patch for BUG#51894 ignores that the trx-cache may have
updates to temporary non-transactional tables that must be written to the
binary log while rolling back the transaction.
      
So we fix this problem by writing the content of the trx-cache to the
binary log while rolling back a transaction if a non-transactional
temporary table was updated and the binary logging format is MIXED.
parent 759aabe3
......@@ -77,11 +77,11 @@ eval UPDATE t2, t1 SET t2.data = CONCAT($data, $data, $data, $data),
connection slave;
--source include/wait_for_slave_sql_to_stop.inc
if (`SELECT @@binlog_format = 'STATEMENT'`)
if (`SELECT @@binlog_format = 'STATEMENT' || @@binlog_format = 'MIXED'`)
{
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
}
if (`SELECT @@binlog_format = 'ROW' || @@binlog_format = 'MIXED'`)
if (`SELECT @@binlog_format = 'ROW'`)
{
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 2;
}
......
......@@ -7,8 +7,6 @@ SET SESSION BINLOG_FORMAT=STATEMENT;
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 written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
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;
......@@ -73,6 +71,9 @@ mysqld-bin.000001 # Table_map # # table_id: # (mysql.ndb_apply_status)
mysqld-bin.000001 # Write_rows # # table_id: #
mysqld-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
mysqld-bin.000001 # Query # # COMMIT
mysqld-bin.000001 # Query # # BEGIN
mysqld-bin.000001 # Query # # use `test`; UPDATE t1m, t1b SET m = 2, b = 3 WHERE n = c
mysqld-bin.000001 # Query # # COMMIT
mysqld-bin.000001 # Query # # use `test`; TRUNCATE t1m
mysqld-bin.000001 # Query # # use `test`; TRUNCATE t1b
mysqld-bin.000001 # Query # # use `test`; TRUNCATE t1n
......
......@@ -635,7 +635,9 @@ 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 */
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
DROP PROCEDURE p1;
DROP TABLE t1;
DROP DATABASE bug39182;
......
......@@ -110,8 +110,6 @@ delete from t2;
reset master;
insert into t1 values(9);
insert into t2 select * from t1;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN
......@@ -126,8 +124,6 @@ reset master;
insert into t1 values(10);
begin;
insert into t2 select * from t1;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query # # BEGIN
......@@ -245,8 +241,6 @@ Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
create table t0 (n int);
insert t0 select * from t1;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
set autocommit=1;
insert into t0 select GET_LOCK("lock1",null);
Warnings:
......@@ -288,7 +282,7 @@ master-bin.000001 # Query # # use `test`; create temporary table t1 (a int) engi
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert t1 values (1)
master-bin.000001 # Query # # ROLLBACK
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # use `test`; create table t0 (n int)
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; insert t0 select * from t1
......
......@@ -8,8 +8,6 @@ SET SESSION BINLOG_FORMAT=STATEMENT;
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 written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
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;
......
......@@ -72,8 +72,6 @@ before call db1.p1()
INSERT INTO db1.t2 VALUES ('before call db1.p2()');
BEGIN;
CALL db1.p2();
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.
ROLLBACK;
INSERT INTO db1.t2 VALUES ('after call db1.p2()');
SELECT * FROM db1.t1;
......
......@@ -29,8 +29,6 @@ UPDATE t SET f = 'magenta 2' WHERE f = 'red';
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
INSERT INTO t VALUES (5 + (2 * 10),"brown");
INSERT INTO n VALUES (now(),"brown");
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.
COMMIT;
ROLLBACK;
Warnings:
......@@ -58,8 +56,6 @@ UPDATE t SET f = 'dark blue 2' WHERE f = 'red';
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
INSERT INTO t VALUES (6 + (2 * 10),"brown");
INSERT INTO n VALUES (now(),"brown");
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.
COMMIT;
COMMIT;
show binlog events from <binlog_start>;
......@@ -83,8 +79,6 @@ UPDATE t SET f = 'magenta 1' WHERE f = 'red';
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
INSERT INTO t VALUES (5 + (1 * 10),"brown");
INSERT INTO n VALUES (now(),"brown");
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.
COMMIT;
ROLLBACK;
Warnings:
......@@ -110,8 +104,6 @@ UPDATE t SET f = 'dark blue 1' WHERE f = 'red';
ERROR HY000: Lock wait timeout exceeded; try restarting transaction
INSERT INTO t VALUES (6 + (1 * 10),"brown");
INSERT INTO n VALUES (now(),"brown");
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.
COMMIT;
COMMIT;
show binlog events from <binlog_start>;
......
......@@ -19,7 +19,7 @@ SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
START SLAVE SQL_THREAD;
*** Single statement on both transactional and non-transactional tables. ***
Got one of the listed errors
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 2;
SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;
START SLAVE SQL_THREAD;
source include/diff_master_slave.inc;
########################################################################################
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -32,18 +32,12 @@ BEGIN;
Got one of the listed errors
Got one of the listed errors
Got one of the listed errors
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.
BEGIN;
Got one of the listed errors
Got one of the listed errors
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.
BEGIN;
Got one of the listed errors
Got one of the listed errors
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.
source include/diff_master_slave.inc;
########################################################################################
# 3 - BEGIN - COMMIT
......@@ -55,8 +49,6 @@ BEGIN;
Got one of the listed errors
Got one of the listed errors
Got one of the listed errors
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.
COMMIT;
source include/diff_master_slave.inc;
########################################################################################
......@@ -69,8 +61,6 @@ BEGIN;
Got one of the listed errors
Got one of the listed errors
Got one of the listed errors
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.
ROLLBACK;
Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
......@@ -109,8 +99,6 @@ BEGIN;
Got one of the listed errors
Got one of the listed errors
Got one of the listed errors
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.
ROLLBACK TO sv;
Warnings:
Warning 1196 Some non-transactional changed tables couldn't be rolled back
......@@ -123,19 +111,11 @@ TRUNCATE TABLE t1;
TRUNCATE TABLE t2;
TRUNCATE TABLE t3;
BEGIN;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.
Got one of the listed errors
Got one of the listed errors
Got one of the listed errors
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.
COMMIT;
BEGIN;
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.
Got one of the listed errors
COMMIT;
source include/diff_master_slave.inc;
......
......@@ -52,8 +52,6 @@ include/start_slave.inc
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 written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
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
......
......@@ -23,8 +23,6 @@ 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 written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
INSERT INTO t_innodb SELECT * FROM t_myisam_temp;
INSERT INTO t_innodb SELECT * FROM t_innodb_temp;
ROLLBACK;
......@@ -32,8 +30,6 @@ 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 written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement accesses nontransactional table as well as transactional or temporary table, and writes to any of them.
INSERT INTO t_innodb SELECT * FROM t_myisam_temp;
INSERT INTO t_innodb SELECT * FROM t_innodb_temp;
ROLLBACK;
......@@ -61,11 +57,15 @@ 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 # # COMMIT
master-bin.000001 # Query # # BEGIN
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 # # COMMIT
master-bin.000001 # Query # # BEGIN
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
......@@ -185,12 +185,8 @@ BEGIN;
INSERT INTO t_myisam VALUES(CONNECTION_ID());
INSERT INTO tmp1 VALUES(1);
INSERT INTO t_myisam VALUES(1);
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.
INSERT INTO t_innodb VALUES(1);
INSERT INTO t_myisam VALUES(CONNECTION_ID());
Warnings:
Note 1592 Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT. Statement is unsafe because it accesses a non-transactional table after accessing a transactional table within the same transaction.
INSERT INTO t_innodb VALUES(1);
COMMIT;
show binlog events from <binlog_start>;
......@@ -202,13 +198,15 @@ master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO t_myisam VALUES(CONNECTION_ID())
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO tmp1 VALUES(1)
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO t_myisam VALUES(1)
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO t_myisam VALUES(CONNECTION_ID())
master-bin.000001 # Query # # COMMIT
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO tmp1 VALUES(1)
master-bin.000001 # Query # # use `test`; INSERT INTO t_innodb VALUES(1)
master-bin.000001 # Query # # use `test`; INSERT INTO t_innodb VALUES(1)
master-bin.000001 # Xid # # COMMIT /* XID */
......
......@@ -11,5 +11,3 @@ SET SESSION binlog_direct_non_transactional_updates = OFF;
--enable_query_log
let $engine_type=Innodb;
--source extra/rpl_tests/rpl_mixing_engines.test
--diff_files suite/rpl/r/rpl_non_direct_mixed_mixing_engines.result suite/rpl/r/rpl_mixed_mixing_engines.result
......@@ -12,6 +12,10 @@
# Save the initial number of concurrent sessions.
--source include/count_sessions.inc
--disable_query_log
CALL mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
--enable_query_log
--echo #
--echo # Test how do we handle locking in various cases when
--echo # we read data from InnoDB tables.
......
......@@ -209,7 +209,7 @@ class binlog_cache_data
{
public:
binlog_cache_data(): m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF),
incident(FALSE)
incident(FALSE), changes_to_non_trans_temp_table_flag(FALSE)
{
cache_log.end_of_file= max_binlog_cache_size;
}
......@@ -245,9 +245,20 @@ class binlog_cache_data
return(incident);
}
void set_changes_to_non_trans_temp_table()
{
changes_to_non_trans_temp_table_flag= TRUE;
}
bool changes_to_non_trans_temp_table()
{
return (changes_to_non_trans_temp_table_flag);
}
void reset()
{
truncate(0);
changes_to_non_trans_temp_table_flag= FALSE;
incident= FALSE;
before_stmt_pos= MY_OFF_T_UNDEF;
cache_log.end_of_file= max_binlog_cache_size;
......@@ -304,6 +315,12 @@ class binlog_cache_data
*/
bool incident;
/*
This flag indicates if the cache has changes to temporary tables.
@TODO This a temporary fix and should be removed after BUG#54562.
*/
bool changes_to_non_trans_temp_table_flag;
/*
It truncates the cache to a certain position. This includes deleting the
pending event.
......@@ -1772,13 +1789,23 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
/*
We flush the cache wrapped in a beging/rollback if:
. 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.
. the OPTION_KEEP_LOG is active or;
. the format is STMT and a non-trans table was updated or;
. the format is MIXED and a temporary non-trans table was
updated or;
. the format is MIXED, non-trans table was updated and
aborting a single statement transaction;
*/
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)))
thd->variables.binlog_format == BINLOG_FORMAT_STMT) ||
(cache_mngr->trx_cache.changes_to_non_trans_temp_table() &&
thd->variables.binlog_format == BINLOG_FORMAT_MIXED) ||
(trans_has_updated_non_trans_table(thd) &&
ending_single_stmt_trans(thd,all) &&
thd->variables.binlog_format == BINLOG_FORMAT_MIXED)))
{
Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE, TRUE, 0);
error= binlog_flush_trx_cache(thd, cache_mngr, &qev);
......@@ -1786,13 +1813,17 @@ static int binlog_rollback(handlerton *hton, THD *thd, bool all)
/*
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.
. the OPTION_KEEP_LOG is not active and;
. the format is not STMT or no non-trans was updated and;
. the format is not MIXED or no temporary non-trans was
updated.
*/
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))))
(!stmt_has_updated_non_trans_table(thd) ||
thd->variables.binlog_format != BINLOG_FORMAT_STMT) &&
(!cache_mngr->trx_cache.changes_to_non_trans_temp_table() ||
thd->variables.binlog_format != BINLOG_FORMAT_MIXED)))
error= binlog_truncate_trx_cache(thd, cache_mngr, all);
}
......@@ -4254,7 +4285,23 @@ bool use_trans_cache(const THD* thd, bool is_transactional)
*/
bool ending_trans(THD* thd, const bool all)
{
return (all || (!all && !thd->in_multi_stmt_transaction_mode()));
return (all || ending_single_stmt_trans(thd, all));
}
/**
This function checks if 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 single statement transaction, otherwise
@c false.
*/
bool ending_single_stmt_trans(THD* thd, const bool all)
{
return (!all && !thd->in_multi_stmt_transaction_mode());
}
/**
......@@ -4653,6 +4700,9 @@ bool MYSQL_BIN_LOG::write(Log_event *event_info)
file= cache_mngr->get_binlog_cache_log(is_trans_cache);
cache_data= cache_mngr->get_binlog_cache_data(is_trans_cache);
if (thd->stmt_accessed_non_trans_temp_table())
cache_data->set_changes_to_non_trans_temp_table();
thd->binlog_start_trans_and_stmt();
}
DBUG_PRINT("info",("event type: %d",event_info->get_type_code()));
......
......@@ -27,6 +27,7 @@ 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 ending_single_stmt_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);
......
......@@ -678,8 +678,9 @@ 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_temporary_used
cache_type= ((using_trans || stmt_has_updated_trans_table(thd) ||
(thd->stmt_accessed_temp_table() &&
trans_has_updated_trans_table(thd)))
? Log_event::EVENT_TRANSACTIONAL_CACHE :
Log_event::EVENT_STMT_CACHE);
}
......@@ -2519,8 +2520,9 @@ Query_log_event::Query_log_event(THD* thd_arg, const char* query_arg,
}
else
{
cache_type= ((using_trans || stmt_has_updated_trans_table(thd)
|| trx_cache || thd->thread_temporary_used)
cache_type= ((using_trans || stmt_has_updated_trans_table(thd) || trx_cache ||
(thd->stmt_accessed_temp_table() &&
trans_has_updated_trans_table(thd)))
? Log_event::EVENT_TRANSACTIONAL_CACHE :
Log_event::EVENT_STMT_CACHE);
}
......
This diff is collapsed.
......@@ -1566,6 +1566,125 @@ class THD :public Statement,
return current_stmt_binlog_format == BINLOG_FORMAT_ROW;
}
enum enum_stmt_accessed_table
{
/*
If a transactional table is about to be read. Note that
a write implies a read.
*/
STMT_READS_TRANS_TABLE= 0,
/*
If a transactional table is about to be updated.
*/
STMT_WRITES_TRANS_TABLE,
/*
If a non-transactional table is about to be read. Note that
a write implies a read.
*/
STMT_READS_NON_TRANS_TABLE,
/*
If a non-transactional table is about to be updated.
*/
STMT_WRITES_NON_TRANS_TABLE,
/*
If a temporary transactional table is about to be read. Note
that a write implies a read.
*/
STMT_READS_TEMP_TRANS_TABLE,
/*
If a temporary transactional table is about to be updated.
*/
STMT_WRITES_TEMP_TRANS_TABLE,
/*
If a temporary non-transactional table is about to be read. Note
that a write implies a read.
*/
STMT_READS_TEMP_NON_TRANS_TABLE,
/*
If a temporary non-transactional table is about to be updated.
*/
STMT_WRITES_TEMP_NON_TRANS_TABLE,
/*
The last element of the enumeration. Please, if necessary add
anything before this.
*/
STMT_ACCESS_TABLE_COUNT
};
/**
Sets the type of table that is about to be accessed while executing a
statement.
@param accessed_table Enumeration type that defines the type of table,
e.g. temporary, transactional, non-transactional.
*/
inline void set_stmt_accessed_table(enum_stmt_accessed_table accessed_table)
{
DBUG_ENTER("THD::set_stmt_accessed_table");
DBUG_ASSERT(accessed_table >= 0 && accessed_table < STMT_ACCESS_TABLE_COUNT);
stmt_accessed_table_flag |= (1U << accessed_table);
DBUG_VOID_RETURN;
}
/**
Checks if a type of table is about to be accessed while executing a
statement.
@param accessed_table Enumeration type that defines the type of table,
e.g. temporary, transactional, non-transactional.
@return
@retval TRUE if the type of the table is about to be accessed
@retval FALSE otherwise
*/
inline bool stmt_accessed_table(enum_stmt_accessed_table accessed_table)
{
DBUG_ENTER("THD::stmt_accessed_table");
DBUG_ASSERT(accessed_table >= 0 && accessed_table < STMT_ACCESS_TABLE_COUNT);
DBUG_RETURN((stmt_accessed_table_flag & (1U << accessed_table)) != 0);
}
/**
Checks if a temporary table is about to be accessed while executing a
statement.
@return
@retval TRUE if a temporary table is about to be accessed
@retval FALSE otherwise
*/
inline bool stmt_accessed_temp_table()
{
DBUG_ENTER("THD::stmt_accessed_temp_table");
DBUG_RETURN((stmt_accessed_table_flag &
((1U << STMT_READS_TEMP_TRANS_TABLE) |
(1U << STMT_WRITES_TEMP_TRANS_TABLE) |
(1U << STMT_READS_TEMP_NON_TRANS_TABLE) |
(1U << STMT_WRITES_TEMP_NON_TRANS_TABLE))) != 0);
}
/**
Checks if a temporary non-transactional table is about to be accessed
while executing a statement.
@return
@retval TRUE if a temporary non-transactional table is about to be
accessed
@retval FALSE otherwise
*/
inline bool stmt_accessed_non_trans_temp_table()
{
DBUG_ENTER("THD::stmt_accessed_non_trans_temp_table");
DBUG_RETURN((stmt_accessed_table_flag &
((1U << STMT_READS_TEMP_NON_TRANS_TABLE) |
(1U << STMT_WRITES_TEMP_NON_TRANS_TABLE))) != 0);
}
private:
/**
Indicates the format in which the current statement will be
......@@ -1603,6 +1722,12 @@ class THD :public Statement,
*/
uint32 binlog_unsafe_warning_flags;
/**
Bit field that determines the type of tables that are about to be
be accessed while executing a statement.
*/
uint32 stmt_accessed_table_flag;
void issue_unsafe_warnings();
/*
......@@ -2021,7 +2146,6 @@ class THD :public Statement,
is set if a statement accesses a temporary table created through
CREATE TEMPORARY TABLE.
*/
bool thread_temporary_used;
bool charset_is_system_charset, charset_is_collation_connection;
bool charset_is_character_set_filesystem;
bool enable_slow_log; /* enable slow log for current statement */
......
......@@ -5633,7 +5633,7 @@ void THD::reset_for_next_command()
thd->transaction.all.modified_non_trans_table= FALSE;
}
DBUG_ASSERT(thd->security_ctx== &thd->main_security_ctx);
thd->thread_specific_used= thd->thread_temporary_used= FALSE;
thd->thread_specific_used= FALSE;
if (opt_bin_log)
{
......@@ -5648,6 +5648,7 @@ void THD::reset_for_next_command()
thd->reset_current_stmt_binlog_format_row();
thd->binlog_unsafe_warning_flags= 0;
thd->stmt_accessed_table_flag= 0;
DBUG_PRINT("debug",
("is_current_stmt_binlog_format_row(): %d",
......
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