diff --git a/mysql-test/r/binlog.result b/mysql-test/r/binlog.result index 6807da16e66..41c75a2067b 100644 --- a/mysql-test/r/binlog.result +++ b/mysql-test/r/binlog.result @@ -1,6 +1,6 @@ drop table if exists t1, t2; reset master; -create table t1 (a int) engine=bdb; +create table t1 (a int) engine=innodb; create table t2 (a int) engine=innodb; begin; insert t1 values (5); @@ -10,11 +10,11 @@ insert t2 values (5); commit; show binlog events from 98; Log_name Pos Event_type Server_id End_log_pos Info -master-bin.000001 # Query 1 # use `test`; create table t1 (a int) engine=bdb +master-bin.000001 # Query 1 # use `test`; create table t1 (a int) engine=innodb master-bin.000001 # Query 1 # use `test`; create table t2 (a int) engine=innodb master-bin.000001 # Query 1 # use `test`; BEGIN master-bin.000001 # Query 1 # use `test`; insert t1 values (5) -master-bin.000001 # Query 1 # use `test`; COMMIT +master-bin.000001 # Xid 1 # COMMIT /* XID */ master-bin.000001 # Query 1 # use `test`; BEGIN master-bin.000001 # Query 1 # use `test`; insert t2 values (5) master-bin.000001 # Xid 1 # COMMIT /* XID */ @@ -133,3 +133,119 @@ master-bin.000001 # Rotate 1 # master-bin.000002;pos=4 show binlog events in 'master-bin.000002' from 98; Log_name Pos Event_type Server_id End_log_pos Info master-bin.000002 # Query 1 # use `test`; drop table t1 +set @ac = @@autocommit; +set autocommit= 0; +reset master; +create table t1(n int) engine=innodb; +begin; +insert into t1 values (1); +insert into t1 values (2); +insert into t1 values (3); +commit; +drop table t1; +show binlog events from 0; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 4 Format_desc 1 98 Server version, Binlog ver: 4 +master-bin.000001 98 Query 1 197 use `test`; create table t1(n int) engine=innodb +master-bin.000001 197 Query 1 265 use `test`; BEGIN +master-bin.000001 265 Query 1 353 use `test`; insert into t1 values (1) +master-bin.000001 353 Query 1 441 use `test`; insert into t1 values (2) +master-bin.000001 441 Query 1 529 use `test`; insert into t1 values (3) +master-bin.000001 529 Xid 1 556 COMMIT /* XID */ +master-bin.000001 556 Query 1 632 use `test`; drop table t1 +set autocommit= 1; +reset master; +create table t1(n int) engine=innodb; +insert into t1 values (1); +insert into t1 values (2); +insert into t1 values (3); +commit; +drop table t1; +show binlog events from 0; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 4 Format_desc 1 98 Server version, Binlog ver: 4 +master-bin.000001 98 Query 1 197 use `test`; create table t1(n int) engine=innodb +master-bin.000001 197 Query 1 285 use `test`; insert into t1 values (1) +master-bin.000001 285 Xid 1 312 COMMIT /* XID */ +master-bin.000001 312 Query 1 400 use `test`; insert into t1 values (2) +master-bin.000001 400 Xid 1 427 COMMIT /* XID */ +master-bin.000001 427 Query 1 515 use `test`; insert into t1 values (3) +master-bin.000001 515 Xid 1 542 COMMIT /* XID */ +master-bin.000001 542 Query 1 618 use `test`; drop table t1 +reset master; +create table t1(n int) engine=myisam; +begin; +insert into t1 values (4); +insert into t1 values (5); +insert into t1 values (6); +commit; +drop table t1; +show binlog events from 0; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 4 Format_desc 1 98 Server version, Binlog ver: 4 +master-bin.000001 98 Query 1 197 use `test`; create table t1(n int) engine=myisam +master-bin.000001 197 Query 1 285 use `test`; insert into t1 values (4) +master-bin.000001 285 Query 1 373 use `test`; insert into t1 values (5) +master-bin.000001 373 Query 1 461 use `test`; insert into t1 values (6) +master-bin.000001 461 Query 1 537 use `test`; drop table t1 +set autocommit= 1; +reset master; +create table t1(n int) engine=innodb; +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 197 +insert into t1 values (1); +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 312 +insert into t1 values (2); +insert into t1 values (3); +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 542 +commit; +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 542 +drop table t1; +show binlog events from 0; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 4 Format_desc 1 98 Server version, Binlog ver: 4 +master-bin.000001 98 Query 1 197 use `test`; create table t1(n int) engine=innodb +master-bin.000001 197 Query 1 285 use `test`; insert into t1 values (1) +master-bin.000001 285 Xid 1 312 COMMIT /* XID */ +master-bin.000001 312 Query 1 400 use `test`; insert into t1 values (2) +master-bin.000001 400 Xid 1 427 COMMIT /* XID */ +master-bin.000001 427 Query 1 515 use `test`; insert into t1 values (3) +master-bin.000001 515 Xid 1 542 COMMIT /* XID */ +master-bin.000001 542 Query 1 618 use `test`; drop table t1 +set autocommit= 0; +reset master; +create table t1(n int) engine=myisam; +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 197 +insert into t1 values (4); +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 285 +insert into t1 values (5); +insert into t1 values (6); +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 461 +commit; +show master status; +File Position Binlog_Do_DB Binlog_Ignore_DB +master-bin.000001 461 +drop table t1; +show binlog events from 0; +Log_name Pos Event_type Server_id End_log_pos Info +master-bin.000001 4 Format_desc 1 98 Server version, Binlog ver: 4 +master-bin.000001 98 Query 1 197 use `test`; create table t1(n int) engine=myisam +master-bin.000001 197 Query 1 285 use `test`; insert into t1 values (4) +master-bin.000001 285 Query 1 373 use `test`; insert into t1 values (5) +master-bin.000001 373 Query 1 461 use `test`; insert into t1 values (6) +master-bin.000001 461 Query 1 537 use `test`; drop table t1 +set session autocommit = @ac; +End of 5.0 tests diff --git a/mysql-test/t/binlog.test b/mysql-test/t/binlog.test index accfa6a577f..6271a8f95a8 100644 --- a/mysql-test/t/binlog.test +++ b/mysql-test/t/binlog.test @@ -3,7 +3,6 @@ # -- source include/have_log_bin.inc -- source include/not_embedded.inc --- source include/have_bdb.inc -- source include/have_innodb.inc -- source include/have_log_bin.inc @@ -12,7 +11,7 @@ drop table if exists t1, t2; --enable_warnings reset master; -create table t1 (a int) engine=bdb; +create table t1 (a int) engine=innodb; create table t2 (a int) engine=innodb; begin; insert t1 values (5); @@ -49,3 +48,93 @@ show binlog events in 'master-bin.000001' from 98; --replace_column 2 # 5 # show binlog events in 'master-bin.000002' from 98; +# +# Bug#22540 - Incorrect value in column End_log_pos of +# SHOW BINLOG EVENTS using InnoDB +# + +# the following tests will show that certain queries now return +# absolute offsets (from binlog start, rather than relative to +# the beginning of the current transaction). under what +# conditions it should be allowed / is sensible to put the +# slider into the middle of a transaction is not our concern +# here; we just guarantee that if and when it's done, the +# user has valid offsets to use. if the setter function still +# wants to throw a "positioning into middle of transaction" +# warning, that's its prerogative and handled elsewhere. + +set @ac = @@autocommit; + +# first show this to work for SHOW BINLOG EVENTS + +set autocommit= 0; +reset master; +create table t1(n int) engine=innodb; +begin; +insert into t1 values (1); +insert into t1 values (2); +insert into t1 values (3); +commit; +drop table t1; +--replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ /Server ver: [^,]*,/Server version,/ +show binlog events from 0; + +set autocommit= 1; +reset master; +create table t1(n int) engine=innodb; +insert into t1 values (1); +insert into t1 values (2); +insert into t1 values (3); +commit; +drop table t1; +--replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ /Server ver: [^,]*,/Server version,/ +show binlog events from 0; + +reset master; +create table t1(n int) engine=myisam; +begin; +insert into t1 values (4); +insert into t1 values (5); +insert into t1 values (6); +commit; +drop table t1; +--replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ /Server ver: [^,]*,/Server version,/ +show binlog events from 0; + +# now show this also works for SHOW MASTER STATUS +# as this is what "mysqldump --master-data=1" uses. + +set autocommit= 1; +reset master; +create table t1(n int) engine=innodb; +show master status; +insert into t1 values (1); +show master status; +insert into t1 values (2); +insert into t1 values (3); +show master status; +commit; +show master status; +drop table t1; +--replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ /Server ver: [^,]*,/Server version,/ +show binlog events from 0; + +set autocommit= 0; +reset master; +create table t1(n int) engine=myisam; +show master status; +insert into t1 values (4); +show master status; +insert into t1 values (5); +insert into t1 values (6); + +show master status; +commit; +show master status; +drop table t1; +--replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ /Server ver: [^,]*,/Server version,/ +show binlog events from 0; + +set session autocommit = @ac; + +--echo End of 5.0 tests diff --git a/sql/log.cc b/sql/log.cc index 818828f9557..465d694ba10 100644 --- a/sql/log.cc +++ b/sql/log.cc @@ -134,7 +134,7 @@ static int binlog_commit(THD *thd, bool all) // we're here because trans_log was flushed in MYSQL_LOG::log_xid() DBUG_RETURN(0); } - if (all) + if (all) { Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE); qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE) @@ -1835,7 +1835,9 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) if (likely(is_open())) // Should always be true { - uint length; + uint length, group, carry, hdr_offs; + long val; + byte header[LOG_EVENT_HEADER_LEN]; /* Log "BEGIN" at the beginning of the transaction. @@ -1867,13 +1869,66 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event) /* Read from the file used to cache the queries .*/ if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0)) goto err; - length=my_b_bytes_in_cache(cache); + + length= my_b_bytes_in_cache(cache); DBUG_EXECUTE_IF("half_binlogged_transaction", length-=100;); + + group= my_b_tell(&log_file); + hdr_offs= carry= 0; + do { + if (likely(carry > 0)) + { + DBUG_ASSERT(carry < LOG_EVENT_HEADER_LEN); + + memcpy(&header[carry], (char *)cache->read_pos, LOG_EVENT_HEADER_LEN - carry); + + val= uint4korr(&header[LOG_POS_OFFSET]) + group; + int4store(&header[LOG_POS_OFFSET], val); + + if (my_b_write(&log_file, header, carry)) + goto err; + + memcpy((char *)cache->read_pos, &header[carry], LOG_EVENT_HEADER_LEN - carry); + + hdr_offs = LOG_EVENT_HEADER_LEN - carry + + uint4korr(&header[EVENT_LEN_OFFSET]); + + carry= 0; + } + + if(likely(length > 0)) + { + do { + DBUG_ASSERT((hdr_offs + max(EVENT_LEN_OFFSET, LOG_POS_OFFSET) + 4) <= length); + + val= uint4korr((char *)cache->read_pos + hdr_offs + LOG_POS_OFFSET) + group; + int4store((char *)cache->read_pos + hdr_offs + LOG_POS_OFFSET, val); + hdr_offs += uint4korr((char *)cache->read_pos + hdr_offs + EVENT_LEN_OFFSET); + + /* header beyond current read-buffer? */ + if (hdr_offs >= length) + { + hdr_offs -= length; + break; + } + + /* split header? */ + if (hdr_offs + LOG_EVENT_HEADER_LEN > length) + { + carry= length - hdr_offs; + + memcpy(header, (char *)cache->read_pos + hdr_offs, carry); + length -= carry; + } + + } while (hdr_offs < length); + } + /* Write data to the binary log file */ if (my_b_write(&log_file, cache->read_pos, length)) - goto err; + goto err; cache->read_pos=cache->read_end; // Mark buffer used up DBUG_EXECUTE_IF("half_binlogged_transaction", goto DBUG_skip_commit;); } while ((length=my_b_fill(cache)));