Bug #37221: SET AUTOCOMMIT=1 does not commit binary log

When setting AUTOCOMMIT=1 after starting a transaction, the binary log
did not commit the outstanding transaction. The reason was that the binary
log commit function saw the values of the new settings, deciding that there
were nothing to commit.

Fixed the problem by moving the implicit commit to before the thread option
flags were changed, so that the binary log sees the old values of the flags
instead of the values they will take after the statement.


mysql-test/extra/binlog_tests/implicit.test:
  New test file to check implicit commits both inside and outside transactions.
mysql-test/suite/binlog/t/binlog_implicit_commit.test:
  Test for implicit commit of SET AUTOCOMMIT and LOCK/UNLOCK TABLES.
sql/set_var.cc:
  Adding code to commit pending transaction before changing option flags.
This commit is contained in:
Mats Kindahl 2009-09-23 13:20:48 +02:00
parent 8249fd6eef
commit 124e830125
4 changed files with 445 additions and 2 deletions

View File

@ -0,0 +1,28 @@
# First part: outside a transaction
RESET MASTER;
eval $prepare;
INSERT INTO t1 VALUES (1);
source include/show_binlog_events.inc;
eval $statement;
source include/show_binlog_events.inc;
if (`select '$cleanup' != ''`) {
eval $cleanup;
}
# Second part: inside a transaction
RESET MASTER;
eval $prepare;
BEGIN;
INSERT INTO t1 VALUES (2);
source include/show_binlog_events.inc;
eval $statement;
source include/show_binlog_events.inc;
INSERT INTO t1 VALUES (3);
source include/show_binlog_events.inc;
COMMIT;
source include/show_binlog_events.inc;
if (`select '$cleanup' != ''`) {
eval $cleanup;
}

View File

@ -0,0 +1,345 @@
CREATE TABLE t1 (id INT) ENGINE = InnoDB;
SET BINLOG_FORMAT = STATEMENT;
RESET MASTER;
SET AUTOCOMMIT = 0;
INSERT INTO t1 VALUES (1);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
SET AUTOCOMMIT = 1;
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 t1 VALUES (1)
master-bin.000001 # Xid # # COMMIT /* XID */
COMMIT;
RESET MASTER;
SET AUTOCOMMIT = 0;
BEGIN;
INSERT INTO t1 VALUES (2);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
SET AUTOCOMMIT = 1;
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 t1 VALUES (2)
master-bin.000001 # Xid # # COMMIT /* XID */
INSERT INTO t1 VALUES (3);
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 t1 VALUES (2)
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3)
master-bin.000001 # Xid # # COMMIT /* XID */
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`; INSERT INTO t1 VALUES (2)
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3)
master-bin.000001 # Xid # # COMMIT /* XID */
COMMIT;
RESET MASTER;
SET AUTOCOMMIT = 1;
INSERT INTO t1 VALUES (1);
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 t1 VALUES (1)
master-bin.000001 # Xid # # COMMIT /* XID */
SET AUTOCOMMIT = 1;
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 t1 VALUES (1)
master-bin.000001 # Xid # # COMMIT /* XID */
COMMIT;
RESET MASTER;
SET AUTOCOMMIT = 1;
BEGIN;
INSERT INTO t1 VALUES (2);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
SET AUTOCOMMIT = 1;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
INSERT INTO t1 VALUES (3);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
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`; INSERT INTO t1 VALUES (2)
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3)
master-bin.000001 # Xid # # COMMIT /* XID */
COMMIT;
RESET MASTER;
SET AUTOCOMMIT = 0;
INSERT INTO t1 VALUES (1);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
SET AUTOCOMMIT = 0;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
COMMIT;
RESET MASTER;
SET AUTOCOMMIT = 0;
BEGIN;
INSERT INTO t1 VALUES (2);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
SET AUTOCOMMIT = 0;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
INSERT INTO t1 VALUES (3);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
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`; INSERT INTO t1 VALUES (2)
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3)
master-bin.000001 # Xid # # COMMIT /* XID */
COMMIT;
RESET MASTER;
SET AUTOCOMMIT = 1;
INSERT INTO t1 VALUES (1);
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 t1 VALUES (1)
master-bin.000001 # Xid # # COMMIT /* XID */
SET AUTOCOMMIT = 0;
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 t1 VALUES (1)
master-bin.000001 # Xid # # COMMIT /* XID */
COMMIT;
RESET MASTER;
SET AUTOCOMMIT = 1;
BEGIN;
INSERT INTO t1 VALUES (2);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
SET AUTOCOMMIT = 0;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
INSERT INTO t1 VALUES (3);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
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`; INSERT INTO t1 VALUES (2)
master-bin.000001 # Query # # use `test`; INSERT INTO t1 VALUES (3)
master-bin.000001 # Xid # # COMMIT /* XID */
COMMIT;
SET BINLOG_FORMAT = ROW;
RESET MASTER;
SET AUTOCOMMIT = 0;
INSERT INTO t1 VALUES (1);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
SET AUTOCOMMIT = 1;
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 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
COMMIT;
RESET MASTER;
SET AUTOCOMMIT = 0;
BEGIN;
INSERT INTO t1 VALUES (2);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
SET AUTOCOMMIT = 1;
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 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
INSERT INTO t1 VALUES (3);
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 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
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 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
COMMIT;
RESET MASTER;
SET AUTOCOMMIT = 1;
INSERT INTO t1 VALUES (1);
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 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
SET AUTOCOMMIT = 1;
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 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
COMMIT;
RESET MASTER;
SET AUTOCOMMIT = 1;
BEGIN;
INSERT INTO t1 VALUES (2);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
SET AUTOCOMMIT = 1;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
INSERT INTO t1 VALUES (3);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
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 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
COMMIT;
RESET MASTER;
SET AUTOCOMMIT = 0;
INSERT INTO t1 VALUES (1);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
SET AUTOCOMMIT = 0;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
COMMIT;
RESET MASTER;
SET AUTOCOMMIT = 0;
BEGIN;
INSERT INTO t1 VALUES (2);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
SET AUTOCOMMIT = 0;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
INSERT INTO t1 VALUES (3);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
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 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
COMMIT;
RESET MASTER;
SET AUTOCOMMIT = 1;
INSERT INTO t1 VALUES (1);
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 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
SET AUTOCOMMIT = 0;
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 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
COMMIT;
RESET MASTER;
SET AUTOCOMMIT = 1;
BEGIN;
INSERT INTO t1 VALUES (2);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
SET AUTOCOMMIT = 0;
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
INSERT INTO t1 VALUES (3);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
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 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
COMMIT;
RESET MASTER;
SET AUTOCOMMIT = 0;
INSERT INTO t1 VALUES (1);
show binlog events from <binlog_start>;
Log_name Pos Event_type Server_id End_log_pos Info
LOCK TABLES t1 WRITE;
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 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
INSERT INTO t1 VALUES (2);
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 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
UNLOCK TABLES;
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 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
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 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
master-bin.000001 # Query # # BEGIN
master-bin.000001 # Table_map # # table_id: # (test.t1)
master-bin.000001 # Write_rows # # table_id: # flags: STMT_END_F
master-bin.000001 # Xid # # COMMIT /* XID */
DROP TABLE t1;

View File

@ -0,0 +1,63 @@
# The purpose of this test is to test that setting autocommit does a
# commit of outstanding transactions and nothing is left pending in
# the transaction cache.
source include/have_log_bin.inc;
source include/have_innodb.inc;
# We need a transactional engine, so let's use InnoDB
CREATE TABLE t1 (id INT) ENGINE = InnoDB;
# Testing SET AUTOCOMMIT
SET BINLOG_FORMAT = STATEMENT;
let $cleanup = COMMIT;
let $prepare = SET AUTOCOMMIT = 0;
let $statement = SET AUTOCOMMIT = 1;
source extra/binlog_tests/implicit.test;
let $prepare = SET AUTOCOMMIT = 1;
let $statement = SET AUTOCOMMIT = 1;
source extra/binlog_tests/implicit.test;
let $prepare = SET AUTOCOMMIT = 0;
let $statement = SET AUTOCOMMIT = 0;
source extra/binlog_tests/implicit.test;
let $prepare = SET AUTOCOMMIT = 1;
let $statement = SET AUTOCOMMIT = 0;
source extra/binlog_tests/implicit.test;
SET BINLOG_FORMAT = ROW;
let $prepare = SET AUTOCOMMIT = 0;
let $statement = SET AUTOCOMMIT = 1;
source extra/binlog_tests/implicit.test;
let $prepare = SET AUTOCOMMIT = 1;
let $statement = SET AUTOCOMMIT = 1;
source extra/binlog_tests/implicit.test;
let $prepare = SET AUTOCOMMIT = 0;
let $statement = SET AUTOCOMMIT = 0;
source extra/binlog_tests/implicit.test;
let $prepare = SET AUTOCOMMIT = 1;
let $statement = SET AUTOCOMMIT = 0;
source extra/binlog_tests/implicit.test;
RESET MASTER;
SET AUTOCOMMIT = 0;
INSERT INTO t1 VALUES (1);
source include/show_binlog_events.inc;
LOCK TABLES t1 WRITE;
source include/show_binlog_events.inc;
INSERT INTO t1 VALUES (2);
source include/show_binlog_events.inc;
UNLOCK TABLES;
source include/show_binlog_events.inc;
COMMIT;
source include/show_binlog_events.inc;
# Cleaning up
DROP TABLE t1;

View File

@ -3054,6 +3054,15 @@ static bool set_option_autocommit(THD *thd, set_var *var)
ulonglong org_options= thd->options;
/*
If we are setting AUTOCOMMIT=1 and it was not already 1, then we
need to commit any outstanding transactions.
*/
if (var->save_result.ulong_value != 0 &&
(thd->options & OPTION_NOT_AUTOCOMMIT) &&
ha_commit(thd))
return 1;
if (var->save_result.ulong_value != 0)
thd->options&= ~((sys_var_thd_bit*) var->var)->bit_flag;
else
@ -3067,8 +3076,6 @@ static bool set_option_autocommit(THD *thd, set_var *var)
thd->options&= ~(ulonglong) (OPTION_BEGIN | OPTION_KEEP_LOG);
thd->transaction.all.modified_non_trans_table= FALSE;
thd->server_status|= SERVER_STATUS_AUTOCOMMIT;
if (ha_commit(thd))
return 1;
}
else
{