mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 21:12:26 +01:00
0697ee265f
Keep track of how many pending XIDs (transactions that are prepared in storage engine and written into binlog, but not yet durably committed on disk in the engine) there are in each binlog. When the count of one binlog drops to zero, write a new binlog checkpoint event, telling which is the oldest binlog with pending XIDs. When doing XA recovery after a crash, check the last binlog checkpoint event, and scan all binlog files from that point onwards for XIDs that must be committed if found in prepared state inside engine. Remove the code in binlog rotation that waits for all prepared XIDs to be committed before writing a new binlog file (this is no longer necessary when recovery can scan multiple binlog files).
654 lines
15 KiB
Text
654 lines
15 KiB
Text
# Check that binlog is ok when a transaction mixes updates to InnoDB and
|
|
# MyISAM.
|
|
# It would be nice to make this a replication test, but in 4.0 the
|
|
# slave is always with --skip-innodb in the testsuite. I (Guilhem) however
|
|
# did some tests manually on a slave; tables are replicated fine and
|
|
# Exec_Master_Log_Pos advances as expected.
|
|
|
|
-- source include/have_log_bin.inc
|
|
-- source include/have_innodb.inc
|
|
|
|
call mtr.add_suppression("Unsafe statement written to the binary log using statement format since BINLOG_FORMAT = STATEMENT");
|
|
|
|
--disable_warnings
|
|
drop table if exists t1, t2;
|
|
--enable_warnings
|
|
|
|
connect (con1,localhost,root,,);
|
|
connect (con2,localhost,root,,);
|
|
|
|
connection con1;
|
|
create table t1 (a int) engine=innodb;
|
|
create table t2 (a int) engine=myisam;
|
|
|
|
reset master;
|
|
|
|
begin;
|
|
insert into t1 values(1);
|
|
insert into t2 select * from t1;
|
|
commit;
|
|
|
|
source include/show_binlog_events.inc;
|
|
|
|
delete from t1;
|
|
delete from t2;
|
|
reset master;
|
|
|
|
begin;
|
|
insert into t1 values(2);
|
|
insert into t2 select * from t1;
|
|
# should say some changes to non-transact1onal tables couldn't be rolled back
|
|
rollback;
|
|
|
|
source include/show_binlog_events.inc;
|
|
|
|
delete from t1;
|
|
delete from t2;
|
|
reset master;
|
|
|
|
begin;
|
|
insert into t1 values(3);
|
|
savepoint my_savepoint;
|
|
insert into t1 values(4);
|
|
insert into t2 select * from t1;
|
|
rollback to savepoint my_savepoint;
|
|
commit;
|
|
|
|
source include/show_binlog_events.inc;
|
|
|
|
delete from t1;
|
|
delete from t2;
|
|
reset master;
|
|
|
|
begin;
|
|
insert into t1 values(5);
|
|
savepoint my_savepoint;
|
|
insert into t1 values(6);
|
|
insert into t2 select * from t1;
|
|
rollback to savepoint my_savepoint;
|
|
insert into t1 values(7);
|
|
commit;
|
|
select a from t1 order by a; # check that savepoints work :)
|
|
|
|
source include/show_binlog_events.inc;
|
|
|
|
# and when ROLLBACK is not explicit?
|
|
delete from t1;
|
|
delete from t2;
|
|
reset master;
|
|
|
|
select get_lock("a",10);
|
|
begin;
|
|
insert into t1 values(8);
|
|
insert into t2 select * from t1;
|
|
disconnect con1;
|
|
|
|
connection con2;
|
|
# We want to SHOW BINLOG EVENTS, to know what was logged. But there is no
|
|
# guarantee that logging of the terminated con1 has been done yet (it may not
|
|
# even be started, so con1 may have not even attempted to lock the binlog yet;
|
|
# so SHOW BINLOG EVENTS may come before con1 does the loggin. To be sure that
|
|
# logging has been done, we use a user lock.
|
|
select get_lock("a",10);
|
|
source include/show_binlog_events.inc;
|
|
|
|
# and when not in a transact1on?
|
|
delete from t1;
|
|
delete from t2;
|
|
reset master;
|
|
|
|
insert into t1 values(9);
|
|
insert into t2 select * from t1;
|
|
|
|
source include/show_binlog_events.inc;
|
|
|
|
# Check that when the query updat1ng the MyISAM table is the first in the
|
|
# transaction, we log it immediately.
|
|
delete from t1;
|
|
delete from t2;
|
|
reset master;
|
|
|
|
insert into t1 values(10); # first make t1 non-empty
|
|
begin;
|
|
insert into t2 select * from t1;
|
|
source include/show_binlog_events.inc;
|
|
insert into t1 values(11);
|
|
commit;
|
|
|
|
source include/show_binlog_events.inc;
|
|
|
|
# Check that things work like before this BEGIN/ROLLBACK code was added,
|
|
# when t2 is INNODB
|
|
|
|
alter table t2 engine=INNODB;
|
|
|
|
delete from t1;
|
|
delete from t2;
|
|
reset master;
|
|
|
|
begin;
|
|
insert into t1 values(12);
|
|
insert into t2 select * from t1;
|
|
commit;
|
|
|
|
source include/show_binlog_events.inc;
|
|
|
|
delete from t1;
|
|
delete from t2;
|
|
reset master;
|
|
|
|
begin;
|
|
insert into t1 values(13);
|
|
insert into t2 select * from t1;
|
|
rollback;
|
|
|
|
source include/show_binlog_events.inc;
|
|
|
|
delete from t1;
|
|
delete from t2;
|
|
reset master;
|
|
|
|
begin;
|
|
insert into t1 values(14);
|
|
savepoint my_savepoint;
|
|
insert into t1 values(15);
|
|
insert into t2 select * from t1;
|
|
rollback to savepoint my_savepoint;
|
|
commit;
|
|
|
|
source include/show_binlog_events.inc;
|
|
|
|
delete from t1;
|
|
delete from t2;
|
|
reset master;
|
|
|
|
begin;
|
|
insert into t1 values(16);
|
|
savepoint my_savepoint;
|
|
insert into t1 values(17);
|
|
insert into t2 select * from t1;
|
|
rollback to savepoint my_savepoint;
|
|
insert into t1 values(18);
|
|
commit;
|
|
select a from t1 order by a; # check that savepoints work :)
|
|
|
|
source include/show_binlog_events.inc;
|
|
|
|
# Test for BUG#5714, where a MyISAM update in the transaction used to
|
|
# release row-level locks in InnoDB
|
|
|
|
connect (con3,localhost,root,,);
|
|
|
|
connection con3;
|
|
delete from t1;
|
|
delete from t2;
|
|
--disable_warnings
|
|
alter table t2 engine=MyISAM;
|
|
--enable_warnings
|
|
insert into t1 values (1);
|
|
begin;
|
|
select * from t1 for update;
|
|
|
|
connection con2;
|
|
select (@before:=unix_timestamp())*0; # always give repeatable output
|
|
begin;
|
|
send select * from t1 for update;
|
|
|
|
connection con3;
|
|
insert into t2 values (20);
|
|
|
|
connection con2;
|
|
--error 1205
|
|
reap;
|
|
select (@after:=unix_timestamp())*0; # always give repeatable output
|
|
# verify that innodb_lock_wait_timeout was exceeded. When there was
|
|
# the bug, the reap would return immediately after the insert into t2.
|
|
select (@after-@before) >= 2;
|
|
|
|
connection con3;
|
|
commit;
|
|
|
|
connection con2;
|
|
drop table t1,t2;
|
|
commit;
|
|
|
|
# test for BUG#7947 - DO RELEASE_LOCK() not written to binlog on rollback in
|
|
# the middle of a transaction
|
|
|
|
connection con2;
|
|
begin;
|
|
create temporary table ti (a int) engine=innodb;
|
|
rollback;
|
|
insert into ti values(1);
|
|
set autocommit=0;
|
|
create temporary table t1 (a int) engine=myisam;
|
|
commit;
|
|
insert t1 values (1);
|
|
rollback;
|
|
create table t0 (n int);
|
|
insert t0 select * from t1;
|
|
set autocommit=1;
|
|
insert into t0 select GET_LOCK("lock1",null);
|
|
set autocommit=0;
|
|
create table t2 (n int) engine=innodb;
|
|
insert into t2 values (3);
|
|
disconnect con2;
|
|
connection con3;
|
|
select get_lock("lock1",60);
|
|
source include/show_binlog_events.inc;
|
|
do release_lock("lock1");
|
|
drop table t0,t2;
|
|
|
|
# End of 4.1 tests
|
|
|
|
#
|
|
# Test behaviour of CREATE ... SELECT when mixing MyISAM and InnoDB tables
|
|
#
|
|
|
|
set autocommit=0;
|
|
CREATE TABLE t1 (a int, b int) engine=myisam;
|
|
reset master;
|
|
INSERT INTO t1 values (1,1),(1,2);
|
|
--error ER_DUP_ENTRY
|
|
CREATE TABLE t2 (primary key (a)) engine=innodb select * from t1;
|
|
# This should give warning
|
|
DROP TABLE if exists t2;
|
|
INSERT INTO t1 values (3,3);
|
|
--error ER_DUP_ENTRY
|
|
CREATE TEMPORARY TABLE t2 (primary key (a)) engine=innodb select * from t1;
|
|
ROLLBACK;
|
|
# This should give warning
|
|
DROP TABLE IF EXISTS t2;
|
|
|
|
CREATE TABLE t2 (a int, b int, primary key (a)) engine=innodb;
|
|
INSERT INTO t1 VALUES (4,4);
|
|
CREATE TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
|
|
SELECT * from t2;
|
|
TRUNCATE table t2;
|
|
INSERT INTO t1 VALUES (5,5);
|
|
--error ER_DUP_ENTRY
|
|
INSERT INTO t2 select * from t1;
|
|
SELECT * FROM t2;
|
|
DROP TABLE t2;
|
|
|
|
INSERT INTO t1 values (6,6);
|
|
CREATE TEMPORARY TABLE t2 (a int, b int, primary key (a)) engine=innodb ;
|
|
INSERT INTO t1 values (7,7);
|
|
ROLLBACK;
|
|
INSERT INTO t1 values (8,8);
|
|
CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
|
|
COMMIT;
|
|
INSERT INTO t1 values (9,9);
|
|
CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
|
|
ROLLBACK;
|
|
SELECT * from t2;
|
|
TRUNCATE table t2;
|
|
INSERT INTO t1 values (10,10);
|
|
--error ER_DUP_ENTRY
|
|
INSERT INTO t2 select * from t1;
|
|
SELECT * from t1;
|
|
INSERT INTO t2 values (100,100);
|
|
CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
|
|
COMMIT;
|
|
INSERT INTO t2 values (101,101);
|
|
CREATE TEMPORARY TABLE IF NOT EXISTS t2 (primary key (a)) engine=innodb select * from t1;
|
|
ROLLBACK;
|
|
SELECT * from t2;
|
|
DROP TABLE t1,t2;
|
|
source include/show_binlog_events.inc;
|
|
|
|
# Test for BUG#16559 (ROLLBACK should always have a zero error code in
|
|
# binlog). Has to be here and not earlier, as the SELECTs influence
|
|
# XIDs differently between normal and ps-protocol (and SHOW BINLOG
|
|
# EVENTS above read XIDs).
|
|
|
|
connect (con4,localhost,root,,);
|
|
connection con3;
|
|
reset master;
|
|
create table t1 (a int) engine=innodb;
|
|
create table t2 (a int) engine=myisam;
|
|
select get_lock("a",10);
|
|
begin;
|
|
insert into t1 values(8);
|
|
insert into t2 select * from t1;
|
|
|
|
disconnect con3;
|
|
|
|
connection con4;
|
|
select get_lock("a",10); # wait for rollback to finish
|
|
if (`select @@binlog_format = 'STATEMENT' || @@binlog_format = 'MIXED'`)
|
|
{
|
|
--let $binlog_rollback= query_get_value(SHOW BINLOG EVENTS, Pos, 8)
|
|
--let $binlog_query= query_get_value(SHOW BINLOG EVENTS, Info, 8)
|
|
if ($binlog_query != ROLLBACK) {
|
|
--echo Wrong query from SHOW BINLOG EVENTS. Expected ROLLBACK, got '$binlog_query'
|
|
--source include/show_rpl_debug_info.inc
|
|
--die Wrong value for slave parameter
|
|
}
|
|
}
|
|
flush logs;
|
|
|
|
let $MYSQLD_DATADIR= `select @@datadir`;
|
|
# we check that the error code of the "ROLLBACK" event is 0 and not
|
|
# ER_SERVER_SHUTDOWN (i.e. disconnection just rolls back transaction
|
|
# and does not make slave to stop)
|
|
|
|
-- source include/binlog_start_pos.inc
|
|
|
|
if (`select @@binlog_format = 'ROW'`)
|
|
{
|
|
--echo There is nothing to roll back; transactional changes are removed from the trans cache.
|
|
}
|
|
|
|
if (`select @@binlog_format = 'STATEMENT' || @@binlog_format = 'MIXED'`)
|
|
{
|
|
--exec $MYSQL_BINLOG --start-position=$binlog_rollback $MYSQLD_DATADIR/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output
|
|
|
|
--replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR
|
|
eval select
|
|
(@a:=load_file("$MYSQLTEST_VARDIR/tmp/mix_innodb_myisam_binlog.output"))
|
|
is not null;
|
|
--replace_result $MYSQL_TEST_DIR MYSQL_TEST_DIR
|
|
eval select
|
|
@a like "%#%error_code=0%ROLLBACK\\n/*!*/;%ROLLBACK /* added by mysqlbinlog */;%" OR
|
|
@a like "%#%error_code=0%ROLLBACK\\r\\n/*!*/;%ROLLBACK /* added by mysqlbinlog */;%",
|
|
@a not like "%#%error_code=%error_code=%";
|
|
}
|
|
drop table t1, t2;
|
|
|
|
#
|
|
# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack
|
|
# bug #28960 non-trans temp table changes with insert .. select
|
|
# not binlogged after rollback
|
|
#
|
|
# testing appearence of insert into temp_table in binlog.
|
|
# There are two branches of execution that require different setup.
|
|
|
|
## send_eof() branch
|
|
|
|
# prepare
|
|
|
|
create temporary table tt (a int unique);
|
|
create table ti (a int) engine=innodb;
|
|
reset master;
|
|
|
|
# action
|
|
|
|
begin;
|
|
insert into ti values (1);
|
|
insert into ti values (2) ;
|
|
# This is SAFE because --binlog-direct-non-transactional-updates=FALSE
|
|
insert into tt select * from ti;
|
|
rollback;
|
|
|
|
# check
|
|
|
|
select count(*) from tt /* 2 */;
|
|
source include/show_binlog_events.inc;
|
|
select count(*) from ti /* zero */;
|
|
insert into ti select * from tt;
|
|
select * from ti /* that is what slave would miss - a bug */;
|
|
|
|
|
|
## send_error() branch
|
|
delete from ti;
|
|
delete from tt where a=1;
|
|
reset master;
|
|
|
|
# action
|
|
|
|
begin;
|
|
insert into ti values (1);
|
|
insert into ti values (2) /* to make the dup error in the following */;
|
|
--error ER_DUP_ENTRY
|
|
insert into tt select * from ti /* one affected and error */;
|
|
rollback;
|
|
|
|
# check
|
|
|
|
source include/show_binlog_events.inc;
|
|
select count(*) from ti /* zero */;
|
|
insert into ti select * from tt;
|
|
select * from tt /* that is what otherwise slave missed - the bug */;
|
|
|
|
drop table ti, tt;
|
|
|
|
|
|
#
|
|
# Bug #27417 thd->no_trans_update.stmt lost value inside of SF-exec-stack
|
|
#
|
|
# Testing asserts: if there is a side effect of modifying non-transactional
|
|
# table thd->no_trans_update.stmt must be TRUE;
|
|
# the assert is active with debug build
|
|
#
|
|
|
|
--disable_warnings
|
|
drop function if exists bug27417;
|
|
drop table if exists t1,t2;
|
|
--enable_warnings
|
|
# side effect table
|
|
CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM;
|
|
# target tables
|
|
CREATE TABLE t2 (a int NOT NULL auto_increment, PRIMARY KEY (a));
|
|
|
|
delimiter |;
|
|
create function bug27417(n int)
|
|
RETURNS int(11)
|
|
begin
|
|
insert into t1 values (null);
|
|
return n;
|
|
end|
|
|
delimiter ;|
|
|
|
|
reset master;
|
|
|
|
# execute
|
|
|
|
insert into t2 values (bug27417(1));
|
|
insert into t2 select bug27417(2);
|
|
reset master;
|
|
|
|
--error ER_DUP_ENTRY
|
|
insert into t2 values (bug27417(2));
|
|
source include/show_binlog_events.inc; /* only (!) with fixes for #23333 will show there is the query */;
|
|
select count(*) from t1 /* must be 3 */;
|
|
|
|
reset master;
|
|
select count(*) from t2;
|
|
delete from t2 where a=bug27417(3);
|
|
select count(*) from t2 /* nothing got deleted */;
|
|
source include/show_binlog_events.inc; /* the query must be in regardless of #23333 */;
|
|
select count(*) from t1 /* must be 5 */;
|
|
|
|
--enable_info
|
|
delete t2 from t2 where t2.a=bug27417(100) /* must not affect t2 */;
|
|
--disable_info
|
|
select count(*) from t1 /* must be 7 */;
|
|
|
|
# function bug27417 remains for the following testing of bug#23333
|
|
drop table t1,t2;
|
|
|
|
#
|
|
# Bug#23333 using the patch (and the test) for bug#27471
|
|
#
|
|
# throughout the bug tests
|
|
# t1 - non-trans side effects gatherer;
|
|
# t2 - transactional table;
|
|
#
|
|
|
|
CREATE TABLE t1 (a int NOT NULL auto_increment primary key) ENGINE=MyISAM;
|
|
CREATE TABLE t2 (a int, PRIMARY KEY (a)) ENGINE=InnoDB;
|
|
CREATE TABLE t3 (a int, PRIMARY KEY (a), b int unique) ENGINE=MyISAM;
|
|
CREATE TABLE t4 (a int, PRIMARY KEY (a), b int unique) ENGINE=Innodb;
|
|
CREATE TABLE t5 (a int, PRIMARY KEY (a)) ENGINE=InnoDB;
|
|
|
|
|
|
#
|
|
# INSERT
|
|
#
|
|
|
|
# prepare
|
|
|
|
insert into t2 values (1);
|
|
reset master;
|
|
|
|
# execute
|
|
|
|
--error ER_DUP_ENTRY
|
|
insert into t2 values (bug27417(1));
|
|
|
|
# check
|
|
|
|
source include/show_binlog_events.inc; /* the output must denote there is the query */;
|
|
select count(*) from t1 /* must be 1 */;
|
|
|
|
#
|
|
# INSERT SELECT
|
|
#
|
|
|
|
# prepare
|
|
delete from t1;
|
|
delete from t2;
|
|
insert into t2 values (2);
|
|
reset master;
|
|
|
|
# execute
|
|
|
|
--error ER_DUP_ENTRY
|
|
insert into t2 select bug27417(1) union select bug27417(2);
|
|
|
|
# check
|
|
|
|
source include/show_binlog_events.inc; /* the output must denote there is the query */;
|
|
select count(*) from t1 /* must be 2 */;
|
|
|
|
#
|
|
# UPDATE inc multi-update
|
|
#
|
|
|
|
# prepare
|
|
delete from t1;
|
|
insert into t3 values (1,1),(2,3),(3,4);
|
|
reset master;
|
|
|
|
# execute
|
|
--error ER_DUP_ENTRY
|
|
update t3 set b=b+bug27417(1);
|
|
|
|
# check
|
|
source include/show_binlog_events.inc; /* the output must denote there is the query */;
|
|
select count(*) from t1 /* must be 2 */;
|
|
|
|
## multi_update::send_eof() branch
|
|
|
|
# prepare
|
|
delete from t3;
|
|
delete from t4;
|
|
insert into t3 values (1,1);
|
|
insert into t4 values (1,1),(2,2);
|
|
|
|
reset master;
|
|
|
|
# execute
|
|
--error ER_DUP_ENTRY
|
|
UPDATE t4,t3 SET t4.a=t3.a + bug27417(1) /* top level non-ta table */;
|
|
|
|
# check
|
|
source include/show_binlog_events.inc; /* the output must denote there is the query */;
|
|
select count(*) from t1 /* must be 4 */;
|
|
|
|
## send_error() branch of multi_update
|
|
|
|
# prepare
|
|
delete from t1;
|
|
delete from t3;
|
|
delete from t4;
|
|
insert into t3 values (1,1),(2,2);
|
|
insert into t4 values (1,1),(2,2);
|
|
|
|
reset master;
|
|
|
|
# execute
|
|
--error ER_DUP_ENTRY
|
|
UPDATE t3,t4 SET t3.a=t4.a + bug27417(1);
|
|
|
|
# check
|
|
select count(*) from t1 /* must be 1 */;
|
|
|
|
# cleanup
|
|
drop table t4;
|
|
|
|
|
|
#
|
|
# DELETE incl multi-delete
|
|
#
|
|
|
|
# prepare
|
|
delete from t1;
|
|
delete from t2;
|
|
delete from t3;
|
|
insert into t2 values (1);
|
|
insert into t3 values (1,1);
|
|
create trigger trg_del before delete on t2 for each row
|
|
insert into t3 values (bug27417(1), 2);
|
|
reset master;
|
|
|
|
# execute
|
|
--error ER_DUP_ENTRY
|
|
delete from t2;
|
|
# check
|
|
source include/show_binlog_events.inc; /* the output must denote there is the query */;
|
|
select count(*) from t1 /* must be 1 */;
|
|
|
|
# cleanup
|
|
drop trigger trg_del;
|
|
|
|
# prepare
|
|
delete from t1;
|
|
delete from t2;
|
|
delete from t5;
|
|
create trigger trg_del_t2 after delete on t2 for each row
|
|
insert into t1 values (1);
|
|
insert into t2 values (2),(3);
|
|
insert into t5 values (1),(2);
|
|
reset master;
|
|
|
|
# execute
|
|
--error ER_DUP_ENTRY
|
|
delete t2.* from t2,t5 where t2.a=t5.a + 1;
|
|
|
|
# check
|
|
source include/show_binlog_events.inc; /* the output must denote there is the query */;
|
|
select count(*) from t1 /* must be 1 */;
|
|
|
|
|
|
#
|
|
# LOAD DATA
|
|
#
|
|
|
|
# prepare
|
|
delete from t1;
|
|
create table t4 (a int default 0, b int primary key) engine=innodb;
|
|
insert into t4 values (0, 17);
|
|
reset master;
|
|
|
|
# execute
|
|
--error ER_DUP_ENTRY
|
|
load data infile '../../std_data/rpl_loaddata.dat' into table t4 (a, @b) set b= @b + bug27417(2);
|
|
# check
|
|
select * from t4;
|
|
select count(*) from t1 /* must be 2 */;
|
|
source include/show_binlog_events.inc; /* the output must denote there is the query */;
|
|
|
|
#
|
|
# bug#23333 cleanup
|
|
#
|
|
|
|
|
|
drop trigger trg_del_t2;
|
|
drop table t1,t2,t3,t4,t5;
|
|
drop function bug27417;
|
|
|
|
|
|
--echo end of tests
|
|
|