mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
Merge gbichot@bk-internal.mysql.com:/home/bk/mysql-4.0
into mysql.com:/home/mysql_src/mysql-4.0
This commit is contained in:
@ -1459,9 +1459,8 @@ int main(int argc, char **argv)
|
|||||||
fprintf(md_result_file,
|
fprintf(md_result_file,
|
||||||
"\n--\n-- Position to start replication from\n--\n\n");
|
"\n--\n-- Position to start replication from\n--\n\n");
|
||||||
fprintf(md_result_file,
|
fprintf(md_result_file,
|
||||||
"CHANGE MASTER TO MASTER_LOG_FILE='%s' ;\n", row[0]);
|
"CHANGE MASTER TO MASTER_LOG_FILE='%s', \
|
||||||
fprintf(md_result_file, "CHANGE MASTER TO MASTER_LOG_POS=%s ;\n",
|
MASTER_LOG_POS=%s ;\n",row[0],row[1]);
|
||||||
row[1]);
|
|
||||||
}
|
}
|
||||||
mysql_free_result(master);
|
mysql_free_result(master);
|
||||||
}
|
}
|
||||||
|
180
mysql-test/r/mix_innodb_myisam_binlog.result
Normal file
180
mysql-test/r/mix_innodb_myisam_binlog.result
Normal file
@ -0,0 +1,180 @@
|
|||||||
|
drop table if exists ti, tm;
|
||||||
|
create table ti (a int) type=innodb;
|
||||||
|
create table tm (a int) type=myisam;
|
||||||
|
reset master;
|
||||||
|
begin;
|
||||||
|
insert into ti values(1);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
commit;
|
||||||
|
show binlog events from 79;
|
||||||
|
Log_name Pos Event_type Server_id Orig_log_pos Info
|
||||||
|
master-bin.001 79 Query 1 79 use test; BEGIN
|
||||||
|
master-bin.001 119 Query 1 79 use test; insert into ti values(1)
|
||||||
|
master-bin.001 178 Query 1 79 use test; insert into tm select * from ti
|
||||||
|
master-bin.001 244 Query 1 244 use test; COMMIT
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
begin;
|
||||||
|
insert into ti values(2);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
rollback;
|
||||||
|
Warning: Some non-transactional changed tables couldn't be rolled back
|
||||||
|
show binlog events from 79;
|
||||||
|
Log_name Pos Event_type Server_id Orig_log_pos Info
|
||||||
|
master-bin.001 79 Query 1 79 use test; BEGIN
|
||||||
|
master-bin.001 119 Query 1 79 use test; insert into ti values(2)
|
||||||
|
master-bin.001 178 Query 1 79 use test; insert into tm select * from ti
|
||||||
|
master-bin.001 244 Query 1 244 use test; ROLLBACK
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
begin;
|
||||||
|
insert into ti values(3);
|
||||||
|
savepoint my_savepoint;
|
||||||
|
insert into ti values(4);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
rollback to savepoint my_savepoint;
|
||||||
|
Warning: Some non-transactional changed tables couldn't be rolled back
|
||||||
|
commit;
|
||||||
|
show binlog events from 79;
|
||||||
|
Log_name Pos Event_type Server_id Orig_log_pos Info
|
||||||
|
master-bin.001 79 Query 1 79 use test; BEGIN
|
||||||
|
master-bin.001 119 Query 1 79 use test; insert into ti values(3)
|
||||||
|
master-bin.001 178 Query 1 79 use test; savepoint my_savepoint
|
||||||
|
master-bin.001 235 Query 1 79 use test; insert into ti values(4)
|
||||||
|
master-bin.001 294 Query 1 79 use test; insert into tm select * from ti
|
||||||
|
master-bin.001 360 Query 1 79 use test; rollback to savepoint my_savepoint
|
||||||
|
master-bin.001 429 Query 1 429 use test; COMMIT
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
begin;
|
||||||
|
insert into ti values(5);
|
||||||
|
savepoint my_savepoint;
|
||||||
|
insert into ti values(6);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
rollback to savepoint my_savepoint;
|
||||||
|
Warning: Some non-transactional changed tables couldn't be rolled back
|
||||||
|
insert into ti values(7);
|
||||||
|
commit;
|
||||||
|
select a from ti order by a;
|
||||||
|
a
|
||||||
|
5
|
||||||
|
7
|
||||||
|
show binlog events from 79;
|
||||||
|
Log_name Pos Event_type Server_id Orig_log_pos Info
|
||||||
|
master-bin.001 79 Query 1 79 use test; BEGIN
|
||||||
|
master-bin.001 119 Query 1 79 use test; insert into ti values(5)
|
||||||
|
master-bin.001 178 Query 1 79 use test; savepoint my_savepoint
|
||||||
|
master-bin.001 235 Query 1 79 use test; insert into ti values(6)
|
||||||
|
master-bin.001 294 Query 1 79 use test; insert into tm select * from ti
|
||||||
|
master-bin.001 360 Query 1 79 use test; rollback to savepoint my_savepoint
|
||||||
|
master-bin.001 429 Query 1 79 use test; insert into ti values(7)
|
||||||
|
master-bin.001 488 Query 1 488 use test; COMMIT
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
select get_lock("a",10);
|
||||||
|
get_lock("a",10)
|
||||||
|
1
|
||||||
|
begin;
|
||||||
|
insert into ti values(8);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
select get_lock("a",10);
|
||||||
|
get_lock("a",10)
|
||||||
|
1
|
||||||
|
show binlog events from 79;
|
||||||
|
Log_name Pos Event_type Server_id Orig_log_pos Info
|
||||||
|
master-bin.001 79 Query 1 79 use test; BEGIN
|
||||||
|
master-bin.001 119 Query 1 79 use test; insert into ti values(8)
|
||||||
|
master-bin.001 178 Query 1 79 use test; insert into tm select * from ti
|
||||||
|
master-bin.001 244 Query 1 244 use test; ROLLBACK
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
insert into ti values(9);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
show binlog events from 79;
|
||||||
|
Log_name Pos Event_type Server_id Orig_log_pos Info
|
||||||
|
master-bin.001 79 Query 1 79 use test; insert into ti values(9)
|
||||||
|
master-bin.001 138 Query 1 138 use test; insert into tm select * from ti
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
insert into ti values(10);
|
||||||
|
begin;
|
||||||
|
insert into tm select * from ti;
|
||||||
|
show binlog events from 79;
|
||||||
|
Log_name Pos Event_type Server_id Orig_log_pos Info
|
||||||
|
master-bin.001 79 Query 1 79 use test; insert into ti values(10)
|
||||||
|
master-bin.001 139 Query 1 139 use test; insert into tm select * from ti
|
||||||
|
insert into ti values(11);
|
||||||
|
commit;
|
||||||
|
show binlog events from 79;
|
||||||
|
Log_name Pos Event_type Server_id Orig_log_pos Info
|
||||||
|
master-bin.001 79 Query 1 79 use test; insert into ti values(10)
|
||||||
|
master-bin.001 139 Query 1 139 use test; insert into tm select * from ti
|
||||||
|
master-bin.001 205 Query 1 205 use test; BEGIN
|
||||||
|
master-bin.001 245 Query 1 205 use test; insert into ti values(11)
|
||||||
|
master-bin.001 305 Query 1 305 use test; COMMIT
|
||||||
|
alter table tm type=INNODB;
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
begin;
|
||||||
|
insert into ti values(12);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
commit;
|
||||||
|
show binlog events from 79;
|
||||||
|
Log_name Pos Event_type Server_id Orig_log_pos Info
|
||||||
|
master-bin.001 79 Query 1 79 use test; BEGIN
|
||||||
|
master-bin.001 119 Query 1 79 use test; insert into ti values(12)
|
||||||
|
master-bin.001 179 Query 1 79 use test; insert into tm select * from ti
|
||||||
|
master-bin.001 245 Query 1 245 use test; COMMIT
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
begin;
|
||||||
|
insert into ti values(13);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
rollback;
|
||||||
|
show binlog events from 79;
|
||||||
|
Log_name Pos Event_type Server_id Orig_log_pos Info
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
begin;
|
||||||
|
insert into ti values(14);
|
||||||
|
savepoint my_savepoint;
|
||||||
|
insert into ti values(15);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
rollback to savepoint my_savepoint;
|
||||||
|
commit;
|
||||||
|
show binlog events from 79;
|
||||||
|
Log_name Pos Event_type Server_id Orig_log_pos Info
|
||||||
|
master-bin.001 79 Query 1 79 use test; BEGIN
|
||||||
|
master-bin.001 119 Query 1 79 use test; insert into ti values(14)
|
||||||
|
master-bin.001 179 Query 1 179 use test; COMMIT
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
begin;
|
||||||
|
insert into ti values(16);
|
||||||
|
savepoint my_savepoint;
|
||||||
|
insert into ti values(17);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
rollback to savepoint my_savepoint;
|
||||||
|
insert into ti values(18);
|
||||||
|
commit;
|
||||||
|
select a from ti order by a;
|
||||||
|
a
|
||||||
|
16
|
||||||
|
18
|
||||||
|
show binlog events from 79;
|
||||||
|
Log_name Pos Event_type Server_id Orig_log_pos Info
|
||||||
|
master-bin.001 79 Query 1 79 use test; BEGIN
|
||||||
|
master-bin.001 119 Query 1 79 use test; insert into ti values(16)
|
||||||
|
master-bin.001 179 Query 1 79 use test; insert into ti values(18)
|
||||||
|
master-bin.001 239 Query 1 239 use test; COMMIT
|
||||||
|
drop table ti,tm;
|
@ -20,9 +20,9 @@ day id category name
|
|||||||
2003-02-22 2461 b a a a @ % ' " a
|
2003-02-22 2461 b a a a @ % ' " a
|
||||||
2003-03-22 2161 c asdf
|
2003-03-22 2161 c asdf
|
||||||
2003-04-22 2416 a bbbbb
|
2003-04-22 2416 a bbbbb
|
||||||
show binlog events from 898;
|
show master status;
|
||||||
Log_name Pos Event_type Server_id Orig_log_pos Info
|
File Position Binlog_do_db Binlog_ignore_db
|
||||||
slave-bin.001 898 Query 1 898 use test; insert into t3 select * from t2
|
slave-bin.001 964
|
||||||
drop table t1;
|
drop table t1;
|
||||||
drop table t2;
|
drop table t2;
|
||||||
drop table t3;
|
drop table t3;
|
||||||
|
175
mysql-test/t/mix_innodb_myisam_binlog.test
Normal file
175
mysql-test/t/mix_innodb_myisam_binlog.test
Normal file
@ -0,0 +1,175 @@
|
|||||||
|
# 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_innodb.inc
|
||||||
|
|
||||||
|
connect (con1,localhost,root,,);
|
||||||
|
connect (con2,localhost,root,,);
|
||||||
|
|
||||||
|
connection con1;
|
||||||
|
|
||||||
|
drop table if exists ti, tm;
|
||||||
|
create table ti (a int) type=innodb;
|
||||||
|
create table tm (a int) type=myisam;
|
||||||
|
|
||||||
|
reset master;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
insert into ti values(1);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
commit;
|
||||||
|
|
||||||
|
show binlog events from 79;
|
||||||
|
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
insert into ti values(2);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
# should say some changes to non-transactional tables couldn't be rolled back
|
||||||
|
--error 1196
|
||||||
|
rollback;
|
||||||
|
|
||||||
|
show binlog events from 79;
|
||||||
|
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
insert into ti values(3);
|
||||||
|
savepoint my_savepoint;
|
||||||
|
insert into ti values(4);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
--error 1196
|
||||||
|
rollback to savepoint my_savepoint;
|
||||||
|
commit;
|
||||||
|
|
||||||
|
show binlog events from 79;
|
||||||
|
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
insert into ti values(5);
|
||||||
|
savepoint my_savepoint;
|
||||||
|
insert into ti values(6);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
--error 1196
|
||||||
|
rollback to savepoint my_savepoint;
|
||||||
|
insert into ti values(7);
|
||||||
|
commit;
|
||||||
|
select a from ti order by a; # check that savepoints work :)
|
||||||
|
|
||||||
|
show binlog events from 79;
|
||||||
|
|
||||||
|
# and when ROLLBACK is not explicit?
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
|
||||||
|
select get_lock("a",10);
|
||||||
|
begin;
|
||||||
|
insert into ti values(8);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
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);
|
||||||
|
show binlog events from 79;
|
||||||
|
|
||||||
|
# and when not in a transaction?
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
|
||||||
|
insert into ti values(9);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
|
||||||
|
show binlog events from 79;
|
||||||
|
|
||||||
|
# Check that when the query updating the MyISAM table is the first in the
|
||||||
|
# transaction, we log it immediately.
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
|
||||||
|
insert into ti values(10); # first make ti non-empty
|
||||||
|
begin;
|
||||||
|
insert into tm select * from ti;
|
||||||
|
show binlog events from 79;
|
||||||
|
insert into ti values(11);
|
||||||
|
commit;
|
||||||
|
|
||||||
|
show binlog events from 79;
|
||||||
|
|
||||||
|
|
||||||
|
# Check that things work like before this BEGIN/ROLLBACK code was added, when tm
|
||||||
|
# is INNODB
|
||||||
|
|
||||||
|
alter table tm type=INNODB;
|
||||||
|
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
insert into ti values(12);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
commit;
|
||||||
|
|
||||||
|
show binlog events from 79;
|
||||||
|
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
insert into ti values(13);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
rollback;
|
||||||
|
|
||||||
|
show binlog events from 79;
|
||||||
|
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
insert into ti values(14);
|
||||||
|
savepoint my_savepoint;
|
||||||
|
insert into ti values(15);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
rollback to savepoint my_savepoint;
|
||||||
|
commit;
|
||||||
|
|
||||||
|
show binlog events from 79;
|
||||||
|
|
||||||
|
delete from ti;
|
||||||
|
delete from tm;
|
||||||
|
reset master;
|
||||||
|
|
||||||
|
begin;
|
||||||
|
insert into ti values(16);
|
||||||
|
savepoint my_savepoint;
|
||||||
|
insert into ti values(17);
|
||||||
|
insert into tm select * from ti;
|
||||||
|
rollback to savepoint my_savepoint;
|
||||||
|
insert into ti values(18);
|
||||||
|
commit;
|
||||||
|
select a from ti order by a; # check that savepoints work :)
|
||||||
|
|
||||||
|
show binlog events from 79;
|
||||||
|
|
||||||
|
drop table ti,tm;
|
@ -32,15 +32,13 @@ sync_with_master;
|
|||||||
select * from t1;
|
select * from t1;
|
||||||
select * from t3;
|
select * from t3;
|
||||||
# We want to be sure that LOAD DATA is in the slave's binlog.
|
# We want to be sure that LOAD DATA is in the slave's binlog.
|
||||||
# But we can't simply read this binlog, because the file_id is uncertain (would
|
# But we can't simply read this binlog, because as the slave has not been
|
||||||
# cause test failures). So instead, we test if the binlog looks long enough to
|
# restarted for this test, the file_id is uncertain (would cause test
|
||||||
|
# failures). So instead, we test if the binlog looks long enough to
|
||||||
# contain LOAD DATA. That is, I (Guilhem) have done SHOW BINLOG EVENTS on my
|
# contain LOAD DATA. That is, I (Guilhem) have done SHOW BINLOG EVENTS on my
|
||||||
# machine, saw that the last event is 'create table t3' and is at position 898
|
# machine, saw that the binlog is of size 964 when things go fine.
|
||||||
# when things go fine. If LOAD DATA was not logged, the binlog would be shorter
|
# If LOAD DATA was not logged, the binlog would be shorter.
|
||||||
# than 898 bytes and there would be an error in SHOW BINLOG EVENTS. Of course,
|
show master status;
|
||||||
# if someone changes the content of '../../std_data/rpl_loaddata2.dat', 898 will
|
|
||||||
# have to be changed too.
|
|
||||||
show binlog events from 898;
|
|
||||||
|
|
||||||
connection master;
|
connection master;
|
||||||
|
|
||||||
|
@ -349,7 +349,7 @@ int ha_commit_trans(THD *thd, THD_TRANS* trans)
|
|||||||
if (trans == &thd->transaction.all && mysql_bin_log.is_open() &&
|
if (trans == &thd->transaction.all && mysql_bin_log.is_open() &&
|
||||||
my_b_tell(&thd->transaction.trans_log))
|
my_b_tell(&thd->transaction.trans_log))
|
||||||
{
|
{
|
||||||
mysql_bin_log.write(thd, &thd->transaction.trans_log);
|
mysql_bin_log.write(thd, &thd->transaction.trans_log, 1);
|
||||||
reinit_io_cache(&thd->transaction.trans_log,
|
reinit_io_cache(&thd->transaction.trans_log,
|
||||||
WRITE_CACHE, (my_off_t) 0, 0, 1);
|
WRITE_CACHE, (my_off_t) 0, 0, 1);
|
||||||
thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
|
thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
|
||||||
@ -432,9 +432,21 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if (trans == &thd->transaction.all)
|
if (trans == &thd->transaction.all)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
Update the binary log with a BEGIN/ROLLBACK block if we have cached some
|
||||||
|
queries and we updated some non-transactional table. Such cases should
|
||||||
|
be rare (updating a non-transactional table inside a transaction...).
|
||||||
|
*/
|
||||||
|
if (unlikely((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
|
||||||
|
mysql_bin_log.is_open() &&
|
||||||
|
my_b_tell(&thd->transaction.trans_log)))
|
||||||
|
mysql_bin_log.write(thd, &thd->transaction.trans_log, 0);
|
||||||
|
/* Flushed or not, empty the binlog cache */
|
||||||
reinit_io_cache(&thd->transaction.trans_log,
|
reinit_io_cache(&thd->transaction.trans_log,
|
||||||
WRITE_CACHE, (my_off_t) 0, 0, 1);
|
WRITE_CACHE, (my_off_t) 0, 0, 1);
|
||||||
thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
|
thd->transaction.trans_log.end_of_file= max_binlog_cache_size;
|
||||||
|
}
|
||||||
thd->variables.tx_isolation=thd->session_tx_isolation;
|
thd->variables.tx_isolation=thd->session_tx_isolation;
|
||||||
if (operation_done)
|
if (operation_done)
|
||||||
{
|
{
|
||||||
@ -448,9 +460,27 @@ int ha_rollback_trans(THD *thd, THD_TRANS *trans)
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Rolls the current transaction back to a savepoint.
|
Rolls the current transaction back to a savepoint.
|
||||||
Return value: 0 if success, 1 if there was not a savepoint of the given
|
Return value: 0 if success, 1 if there was not a savepoint of the given
|
||||||
name.
|
name.
|
||||||
|
NOTE: how do we handle this (unlikely but legal) case:
|
||||||
|
[transaction] + [update to non-trans table] + [rollback to savepoint] ?
|
||||||
|
The problem occurs when a savepoint is before the update to the
|
||||||
|
non-transactional table. Then when there's a rollback to the savepoint, if we
|
||||||
|
simply truncate the binlog cache, we lose the part of the binlog cache where
|
||||||
|
the update is. If we want to not lose it, we need to write the SAVEPOINT
|
||||||
|
command and the ROLLBACK TO SAVEPOINT command to the binlog cache. The latter
|
||||||
|
is easy: it's just write at the end of the binlog cache, but the former should
|
||||||
|
be *inserted* to the place where the user called SAVEPOINT. The solution is
|
||||||
|
that when the user calls SAVEPOINT, we write it to the binlog cache (so no
|
||||||
|
need to later insert it). As transactions are never intermixed in the binary log
|
||||||
|
(i.e. they are serialized), we won't have conflicts with savepoint names when
|
||||||
|
using mysqlbinlog or in the slave SQL thread.
|
||||||
|
Then when ROLLBACK TO SAVEPOINT is called, if we updated some
|
||||||
|
non-transactional table, we don't truncate the binlog cache but instead write
|
||||||
|
ROLLBACK TO SAVEPOINT to it; otherwise we truncate the binlog cache (which
|
||||||
|
will chop the SAVEPOINT command from the binlog cache, which is good as in
|
||||||
|
that case there is no need to have it in the binlog).
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int ha_rollback_to_savepoint(THD *thd, char *savepoint_name)
|
int ha_rollback_to_savepoint(THD *thd, char *savepoint_name)
|
||||||
@ -475,8 +505,24 @@ int ha_rollback_to_savepoint(THD *thd, char *savepoint_name)
|
|||||||
error=1;
|
error=1;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
reinit_io_cache(&thd->transaction.trans_log, WRITE_CACHE,
|
{
|
||||||
binlog_cache_pos, 0, 0);
|
/*
|
||||||
|
Write ROLLBACK TO SAVEPOINT to the binlog cache if we have updated some
|
||||||
|
non-transactional table. Otherwise, truncate the binlog cache starting
|
||||||
|
from the SAVEPOINT command.
|
||||||
|
*/
|
||||||
|
if (unlikely((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) &&
|
||||||
|
mysql_bin_log.is_open() &&
|
||||||
|
my_b_tell(&thd->transaction.trans_log)))
|
||||||
|
{
|
||||||
|
Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE);
|
||||||
|
if (mysql_bin_log.write(&qinfo))
|
||||||
|
error= 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
reinit_io_cache(&thd->transaction.trans_log, WRITE_CACHE,
|
||||||
|
binlog_cache_pos, 0, 0);
|
||||||
|
}
|
||||||
operation_done=1;
|
operation_done=1;
|
||||||
#endif
|
#endif
|
||||||
if (operation_done)
|
if (operation_done)
|
||||||
@ -505,6 +551,13 @@ int ha_savepoint(THD *thd, char *savepoint_name)
|
|||||||
#ifdef HAVE_INNOBASE_DB
|
#ifdef HAVE_INNOBASE_DB
|
||||||
innobase_savepoint(thd,savepoint_name, binlog_cache_pos);
|
innobase_savepoint(thd,savepoint_name, binlog_cache_pos);
|
||||||
#endif
|
#endif
|
||||||
|
/* Write it to the binary log (see comments of ha_rollback_to_savepoint). */
|
||||||
|
if (mysql_bin_log.is_open())
|
||||||
|
{
|
||||||
|
Query_log_event qinfo(thd, thd->query, thd->query_length, TRUE);
|
||||||
|
if (mysql_bin_log.write(&qinfo))
|
||||||
|
error= 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* USING_TRANSACTIONS */
|
#endif /* USING_TRANSACTIONS */
|
||||||
DBUG_RETURN(error);
|
DBUG_RETURN(error);
|
||||||
|
31
sql/log.cc
31
sql/log.cc
@ -1062,7 +1062,17 @@ bool MYSQL_LOG::write(Log_event* event_info)
|
|||||||
bool should_rotate = 0;
|
bool should_rotate = 0;
|
||||||
const char *local_db = event_info->get_db();
|
const char *local_db = event_info->get_db();
|
||||||
#ifdef USING_TRANSACTIONS
|
#ifdef USING_TRANSACTIONS
|
||||||
IO_CACHE *file = ((event_info->get_cache_stmt()) ?
|
/*
|
||||||
|
Should we write to the binlog cache or to the binlog on disk?
|
||||||
|
Write to the binlog cache if:
|
||||||
|
- it is already not empty (meaning we're in a transaction; note that the
|
||||||
|
present event could be about a non-transactional table, but still we need
|
||||||
|
to write to the binlog cache in that case to handle updates to mixed
|
||||||
|
trans/non-trans table types the best possible in binlogging)
|
||||||
|
- or if the event asks for it (cache_stmt == true).
|
||||||
|
*/
|
||||||
|
IO_CACHE *file = ((event_info->get_cache_stmt() ||
|
||||||
|
my_b_tell(&thd->transaction.trans_log)) ?
|
||||||
&thd->transaction.trans_log :
|
&thd->transaction.trans_log :
|
||||||
&log_file);
|
&log_file);
|
||||||
#else
|
#else
|
||||||
@ -1258,6 +1268,13 @@ uint MYSQL_LOG::next_file_id()
|
|||||||
/*
|
/*
|
||||||
Write a cached log entry to the binary log
|
Write a cached log entry to the binary log
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
write()
|
||||||
|
thd
|
||||||
|
cache The cache to copy to the binlog
|
||||||
|
commit_or_rollback If true, will write "COMMIT" in the end, if false will
|
||||||
|
write "ROLLBACK".
|
||||||
|
|
||||||
NOTE
|
NOTE
|
||||||
- We only come here if there is something in the cache.
|
- We only come here if there is something in the cache.
|
||||||
- The thing in the cache is always a complete transaction
|
- The thing in the cache is always a complete transaction
|
||||||
@ -1265,10 +1282,13 @@ uint MYSQL_LOG::next_file_id()
|
|||||||
|
|
||||||
IMPLEMENTATION
|
IMPLEMENTATION
|
||||||
- To support transaction over replication, we wrap the transaction
|
- To support transaction over replication, we wrap the transaction
|
||||||
with BEGIN/COMMIT in the binary log.
|
with BEGIN/COMMIT or BEGIN/ROLLBACK in the binary log.
|
||||||
|
We want to write a BEGIN/ROLLBACK block when a non-transactional table was
|
||||||
|
updated in a transaction which was rolled back. This is to ensure that the
|
||||||
|
same updates are run on the slave.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache)
|
bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, bool commit_or_rollback)
|
||||||
{
|
{
|
||||||
VOID(pthread_mutex_lock(&LOCK_log));
|
VOID(pthread_mutex_lock(&LOCK_log));
|
||||||
DBUG_ENTER("MYSQL_LOG::write(cache");
|
DBUG_ENTER("MYSQL_LOG::write(cache");
|
||||||
@ -1322,7 +1342,10 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
{
|
{
|
||||||
Query_log_event qinfo(thd, "COMMIT", 6, TRUE);
|
Query_log_event qinfo(thd,
|
||||||
|
commit_or_rollback ? "COMMIT" : "ROLLBACK",
|
||||||
|
commit_or_rollback ? 6 : 8,
|
||||||
|
TRUE);
|
||||||
qinfo.set_log_pos(this);
|
qinfo.set_log_pos(this);
|
||||||
if (qinfo.write(&log_file) || flush_io_cache(&log_file))
|
if (qinfo.write(&log_file) || flush_io_cache(&log_file))
|
||||||
goto err;
|
goto err;
|
||||||
|
@ -1803,7 +1803,7 @@ int Query_log_event::exec_event(struct st_relay_log_info* rli)
|
|||||||
*/
|
*/
|
||||||
if (!strcmp(thd->query,"BEGIN"))
|
if (!strcmp(thd->query,"BEGIN"))
|
||||||
rli->inside_transaction= opt_using_transactions;
|
rli->inside_transaction= opt_using_transactions;
|
||||||
else if (!strcmp(thd->query,"COMMIT"))
|
else if (!(strcmp(thd->query,"COMMIT") && strcmp(thd->query,"ROLLBACK")))
|
||||||
rli->inside_transaction=0;
|
rli->inside_transaction=0;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -140,7 +140,7 @@ public:
|
|||||||
bool write(THD *thd, const char *query, uint query_length,
|
bool write(THD *thd, const char *query, uint query_length,
|
||||||
time_t query_start=0);
|
time_t query_start=0);
|
||||||
bool write(Log_event* event_info); // binary log write
|
bool write(Log_event* event_info); // binary log write
|
||||||
bool write(THD *thd, IO_CACHE *cache);
|
bool write(THD *thd, IO_CACHE *cache, bool commit_or_rollback);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
v stands for vector
|
v stands for vector
|
||||||
|
@ -1367,6 +1367,8 @@ void select_insert::send_error(uint errcode,const char *err)
|
|||||||
table->file->has_transactions());
|
table->file->has_transactions());
|
||||||
mysql_bin_log.write(&qinfo);
|
mysql_bin_log.write(&qinfo);
|
||||||
}
|
}
|
||||||
|
if (!table->tmp_table)
|
||||||
|
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
|
||||||
}
|
}
|
||||||
ha_rollback_stmt(thd);
|
ha_rollback_stmt(thd);
|
||||||
if (info.copied || info.deleted)
|
if (info.copied || info.deleted)
|
||||||
@ -1398,6 +1400,8 @@ bool select_insert::send_eof()
|
|||||||
if (info.copied || info.deleted)
|
if (info.copied || info.deleted)
|
||||||
{
|
{
|
||||||
query_cache_invalidate3(thd, table, 1);
|
query_cache_invalidate3(thd, table, 1);
|
||||||
|
if (!(table->file->has_transactions() || table->tmp_table))
|
||||||
|
thd->options|=OPTION_STATUS_NO_TRANS_UPDATE;
|
||||||
}
|
}
|
||||||
if (error)
|
if (error)
|
||||||
{
|
{
|
||||||
|
@ -2553,7 +2553,16 @@ mysql_execute_command(void)
|
|||||||
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
|
thd->server_status&= ~SERVER_STATUS_IN_TRANS;
|
||||||
if (!ha_rollback(thd))
|
if (!ha_rollback(thd))
|
||||||
{
|
{
|
||||||
if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE)
|
/*
|
||||||
|
If a non-transactional table was updated, warn; don't warn if this is a
|
||||||
|
slave thread (because when a slave thread executes a ROLLBACK, it has
|
||||||
|
been read from the binary log, so it's 100% sure and normal to produce
|
||||||
|
error ER_WARNING_NOT_COMPLETE_ROLLBACK. If we sent the warning to the
|
||||||
|
slave SQL thread, it would not stop the thread but just be printed in
|
||||||
|
the error log; but we don't want users to wonder why they have this
|
||||||
|
message in the error log, so we don't send it.
|
||||||
|
*/
|
||||||
|
if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
|
||||||
send_warning(&thd->net,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
|
send_warning(&thd->net,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
|
||||||
else
|
else
|
||||||
send_ok(&thd->net);
|
send_ok(&thd->net);
|
||||||
@ -2565,7 +2574,7 @@ mysql_execute_command(void)
|
|||||||
case SQLCOM_ROLLBACK_TO_SAVEPOINT:
|
case SQLCOM_ROLLBACK_TO_SAVEPOINT:
|
||||||
if (!ha_rollback_to_savepoint(thd, lex->savepoint_name))
|
if (!ha_rollback_to_savepoint(thd, lex->savepoint_name))
|
||||||
{
|
{
|
||||||
if (thd->options & OPTION_STATUS_NO_TRANS_UPDATE)
|
if ((thd->options & OPTION_STATUS_NO_TRANS_UPDATE) && !thd->slave_thread)
|
||||||
send_warning(&thd->net,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
|
send_warning(&thd->net,ER_WARNING_NOT_COMPLETE_ROLLBACK,0);
|
||||||
else
|
else
|
||||||
send_ok(&thd->net);
|
send_ok(&thd->net);
|
||||||
|
Reference in New Issue
Block a user