mirror of
https://github.com/MariaDB/server.git
synced 2025-11-08 00:28:29 +03:00
We now reset the THD members related to auto_increment+binlog in MYSQL_LOG::write(). This is better than in THD::cleanup_after_query(), which was not able to distinguish between SELECT myfunc1(),myfunc2() and INSERT INTO t SELECT myfunc1(),myfunc2() from a binlogging point of view. Rows_log_event::exec_event() now calls lex_start() instead of mysql_init_query() because the latter now does too much (it resets the binlog format). mysql-test/extra/rpl_tests/rpl_insert_id.test: fix after merge mysql-test/mysql-test-run.pl: -v does not bring useful information when running valgrind; I remove it; if you think it's useful add it back. mysql-test/r/binlog_stm_mix_innodb_myisam.result: Position columns of SHOW BINLOG EVENTS are replaced by # (more robust if the size of an event changes). mysql-test/r/rpl_insert_id.result: fix after merge mysql-test/r/rpl_loaddata.result: The binlog positions change, because one event disappeared; indeed there was this in the binlog (in the current 5.1!): SET INSERT_ID=2; SET INSERT_ID=1; SET TIMESTAMP=1152540671; load data LOCAL INFILE '/tmp/SQL_LOAD_MB-1-2' INTO table t1; Two INSERT_ID events, useless and a bug. Goes away afer cleaning up auto_increment handling. mysql-test/r/rpl_switch_stm_row_mixed.result: INSERT_ID=5 appears, it's a consequence of having merged the fix for BUG#20341 "stored function inserting into one auto_increment puts bad data in slave". In mixed mode, if one substatement of a stored procedure requires row-based, the entire procedure uses row-based (was already true for stored functions); this is a consequence of not doing the resetting of binlog format inside lock_tables() (which didn't work with how the slave thread executes row-based binlog events). mysql-test/t/rpl_switch_stm_row_mixed.test: removing the multi-row delayed insert because in RBR the number of events which it generates, is not repeatable (probably depends on how the delayed thread groups rows, i.e. dependent on timing). sql/ha_partition.cc: update to new prototype sql/ha_partition.h: update to new prototype of the handler:: method. sql/handler.cc: after-merge fixes (manually merging part which was hard to merge in fmtool) sql/log.cc: When we write to the binary log, THD's parameters which influenced this write are reset: stmt_depends_on_first_successful_insert_id_in_prev_stmt and auto_inc_intervals_in_cur_stmt_for_binlog. This is so that future writes are not influenced by those and can write their own values. As a consequence, when we don't write to the binlog we do not reset. This is to abide by the rule that in a complex statement (using triggers etc), the first top- or substatement to generate auto_increment ids wins their writing to the binlog (that writing may be done by the statement itself or by the caller); so for example for INSERT INTO t SELECT myfunc() where myfunc() inserts into auto_increment and INSERT INTO t does not, myfunc() will fill auto_inc_intervals_in_cur_stmt_for_binlog, which will not be reset when myfunc() ends, then INSERT INTO t will write to the binlog and thus write the preserved auto_inc_intervals_in_cur_stmt_for_binlog. sql/log_event.cc: mysql_init_query() does too much now to be called in Rows_log_event::exec_event (it call mysql_reset_thd_for_next_command() which may switch the binlog format now). It's ok to call it in Table_map_log_event::exec_event() but its call must be before setting the binlog format to "row". sql/sql_base.cc: Resetting the binlog format in lock_tables() was a bad idea of mine; it causes problems in execution of row-based binlog events, where the thread sets the binlog format by itself and does not want a next lock_tables() to reset the binlog format. It is also misleading, for a function named lock_tables(), to reset the binlog format. As a consequence of this change, in mixed binlogging mode, a routine is logged either entirely statement-based or entirely row-based, we don't switch in the middle (this was already true for prelocked routines, now it's also true for stored procedures). sql/sql_class.cc: resetting of auto_increment variables used for binlogging is now done when writing to the binary log, no need to do the resetting at the end of the statement. It is also more correct this way; consider SELECT myfunc1(),myfunc2(); where both functions insert into the same auto_increment column. Binlogging is done in 2 events: "SELECT myfunc1()" and "SELECT myfunc2()". So each of those needs to have, in binlog, the INSERT_ID which it inserted. But as the 2 function calls are executed under prelocked mode, the old code didn't reset auto_inc_intervals_in_cur_stmt_for_binlog after the first SELECT was binlogged, and so the INSERT_ID of the first SELECT was binlogged for the first SELECT and (wrong) also for the 2nd SELECT event. stmt_depends_on_first_... has the same logic. sql/sql_class.h: clearer comment sql/sql_delete.cc: unneeded #ifdef. As we temporarily change the binlog format to "statement" before calling mysql_delete(), we must restore it afterwards. sql/sql_insert.cc: after-merge fixes. No need to reset auto_inc_intervals_in_cur_stmt_for_binlog for every row in the delayed insert system thread, because we already reset it when writing to the binlog. sql/sql_parse.cc: unneeded #ifdef
277 lines
7.0 KiB
Plaintext
277 lines
7.0 KiB
Plaintext
###########################################################
|
|
# 2006-02-01: By JBM: Added 1022, ORDER BY
|
|
###########################################################
|
|
# See if queries that use both auto_increment and LAST_INSERT_ID()
|
|
# are replicated well
|
|
############################################################
|
|
# REQUIREMENT
|
|
# Auto increment should work for a table with an auto_increment
|
|
# column and index but without primary key.
|
|
##############################################################
|
|
|
|
|
|
# We also check how the foreign_key_check variable is replicated
|
|
|
|
-- source include/master-slave.inc
|
|
#should work for both SBR and RBR
|
|
|
|
connection master;
|
|
create table t1(a int auto_increment, key(a));
|
|
create table t2(b int auto_increment, c int, key(b));
|
|
insert into t1 values (1),(2),(3);
|
|
insert into t1 values (null);
|
|
insert into t2 values (null,last_insert_id());
|
|
save_master_pos;
|
|
connection slave;
|
|
sync_with_master;
|
|
select * from t1 ORDER BY a;
|
|
select * from t2 ORDER BY b;
|
|
connection master;
|
|
#check if multi-line inserts,
|
|
#which set last_insert_id to the first id inserted,
|
|
#are replicated the same way
|
|
drop table t1;
|
|
drop table t2;
|
|
--disable_warnings
|
|
eval create table t1(a int auto_increment, key(a)) engine=$engine_type;
|
|
eval create table t2(b int auto_increment, c int, key(b), foreign key(b) references t1(a)) engine=$engine_type;
|
|
--enable_warnings
|
|
SET FOREIGN_KEY_CHECKS=0;
|
|
insert into t1 values (10);
|
|
insert into t1 values (null),(null),(null);
|
|
insert into t2 values (5,0);
|
|
insert into t2 values (null,last_insert_id());
|
|
SET FOREIGN_KEY_CHECKS=1;
|
|
save_master_pos;
|
|
connection slave;
|
|
sync_with_master;
|
|
select * from t1;
|
|
select * from t2;
|
|
connection master;
|
|
|
|
# check if INSERT SELECT in auto_increment is well replicated (bug #490)
|
|
|
|
drop table t2;
|
|
drop table t1;
|
|
create table t1(a int auto_increment, key(a));
|
|
create table t2(b int auto_increment, c int, key(b));
|
|
insert into t1 values (10);
|
|
insert into t1 values (null),(null),(null);
|
|
insert into t2 values (5,0);
|
|
insert into t2 (c) select * from t1 ORDER BY a;
|
|
select * from t2 ORDER BY b;
|
|
save_master_pos;
|
|
connection slave;
|
|
sync_with_master;
|
|
select * from t1 ORDER BY a;
|
|
select * from t2 ORDER BY b;
|
|
connection master;
|
|
drop table t1;
|
|
drop table t2;
|
|
save_master_pos;
|
|
connection slave;
|
|
sync_with_master;
|
|
|
|
#
|
|
# Bug#8412: Error codes reported in binary log for CHARACTER SET,
|
|
# FOREIGN_KEY_CHECKS
|
|
#
|
|
connection master;
|
|
SET TIMESTAMP=1000000000;
|
|
CREATE TABLE t1 ( a INT UNIQUE );
|
|
SET FOREIGN_KEY_CHECKS=0;
|
|
# Duplicate Key Errors
|
|
--error 1022, 1062
|
|
INSERT INTO t1 VALUES (1),(1);
|
|
sync_slave_with_master;
|
|
|
|
# End of 4.1 tests
|
|
|
|
|
|
#
|
|
# BUG#15728: LAST_INSERT_ID function inside a stored function returns 0
|
|
#
|
|
# The solution is not to reset last_insert_id on enter to sub-statement.
|
|
#
|
|
connection master;
|
|
--disable_warnings
|
|
drop function if exists bug15728;
|
|
drop function if exists bug15728_insert;
|
|
drop table if exists t1, t2;
|
|
--enable_warnings
|
|
|
|
create table t1 (
|
|
id int not null auto_increment,
|
|
last_id int,
|
|
primary key (id)
|
|
);
|
|
create function bug15728() returns int(11)
|
|
return last_insert_id();
|
|
|
|
insert into t1 (last_id) values (0);
|
|
insert into t1 (last_id) values (last_insert_id());
|
|
insert into t1 (last_id) values (bug15728());
|
|
|
|
# Check that nested call replicates too.
|
|
create table t2 (
|
|
id int not null auto_increment,
|
|
last_id int,
|
|
primary key (id)
|
|
);
|
|
delimiter |;
|
|
create function bug15728_insert() returns int(11) modifies sql data
|
|
begin
|
|
insert into t2 (last_id) values (bug15728());
|
|
return bug15728();
|
|
end|
|
|
create trigger t1_bi before insert on t1 for each row
|
|
begin
|
|
declare res int;
|
|
select bug15728_insert() into res;
|
|
set NEW.last_id = res;
|
|
end|
|
|
delimiter ;|
|
|
|
|
insert into t1 (last_id) values (0);
|
|
|
|
drop trigger t1_bi;
|
|
|
|
# Check that nested call doesn't affect outer context.
|
|
select last_insert_id();
|
|
select bug15728_insert();
|
|
select last_insert_id();
|
|
insert into t1 (last_id) values (bug15728());
|
|
# This should be exactly one greater than in the previous call.
|
|
select last_insert_id();
|
|
|
|
# BUG#20339 - stored procedure using LAST_INSERT_ID() does not
|
|
# replicate statement-based
|
|
--disable_warnings
|
|
drop procedure if exists foo;
|
|
--enable_warnings
|
|
delimiter |;
|
|
create procedure foo()
|
|
begin
|
|
declare res int;
|
|
insert into t2 (last_id) values (bug15728());
|
|
insert into t1 (last_id) values (bug15728());
|
|
end|
|
|
delimiter ;|
|
|
call foo();
|
|
|
|
select * from t1;
|
|
select * from t2;
|
|
save_master_pos;
|
|
connection slave;
|
|
sync_with_master;
|
|
select * from t1;
|
|
select * from t2;
|
|
connection master;
|
|
|
|
drop function bug15728;
|
|
drop function bug15728_insert;
|
|
drop table t1;
|
|
drop procedure foo;
|
|
|
|
# test of BUG#20188 REPLACE or ON DUPLICATE KEY UPDATE in
|
|
# auto_increment breaks binlog
|
|
|
|
create table t1 (n int primary key auto_increment not null,
|
|
b int, unique(b));
|
|
|
|
# First, test that we do not call restore_auto_increment() too early
|
|
# in write_record():
|
|
set sql_log_bin=0;
|
|
insert into t1 values(null,100);
|
|
replace into t1 values(null,50),(null,100),(null,150);
|
|
select * from t1 order by n;
|
|
truncate table t1;
|
|
set sql_log_bin=1;
|
|
|
|
insert into t1 values(null,100);
|
|
select * from t1 order by n;
|
|
sync_slave_with_master;
|
|
# make slave's table autoinc counter bigger
|
|
insert into t1 values(null,200),(null,300);
|
|
delete from t1 where b <> 100;
|
|
# check that slave's table content is identical to master
|
|
select * from t1 order by n;
|
|
# only the auto_inc counter differs.
|
|
|
|
connection master;
|
|
replace into t1 values(null,100),(null,350);
|
|
select * from t1 order by n;
|
|
sync_slave_with_master;
|
|
select * from t1 order by n;
|
|
|
|
# Same test as for REPLACE, but for ON DUPLICATE KEY UPDATE
|
|
|
|
# We first check that if we update a row using a value larger than the
|
|
# table's counter, the counter for next row is bigger than the
|
|
# after-value of the updated row.
|
|
connection master;
|
|
insert into t1 values (NULL,400),(3,500),(NULL,600) on duplicate key UPDATE n=1000;
|
|
select * from t1 order by n;
|
|
sync_slave_with_master;
|
|
select * from t1 order by n;
|
|
|
|
# and now test for the bug:
|
|
connection master;
|
|
drop table t1;
|
|
create table t1 (n int primary key auto_increment not null,
|
|
b int, unique(b));
|
|
insert into t1 values(null,100);
|
|
select * from t1 order by n;
|
|
sync_slave_with_master;
|
|
insert into t1 values(null,200),(null,300);
|
|
delete from t1 where b <> 100;
|
|
select * from t1 order by n;
|
|
|
|
connection master;
|
|
insert into t1 values(null,100),(null,350) on duplicate key update n=2;
|
|
select * from t1 order by n;
|
|
sync_slave_with_master;
|
|
select * from t1 order by n;
|
|
|
|
connection master;
|
|
drop table t1;
|
|
|
|
# End of 5.0 tests
|
|
|
|
# Test for BUG#20341 "stored function inserting into one
|
|
# auto_increment puts bad data in slave"
|
|
|
|
truncate table t2;
|
|
create table t1 (id tinyint primary key); # no auto_increment
|
|
|
|
delimiter |;
|
|
create function insid() returns int
|
|
begin
|
|
insert into t2 (last_id) values (0);
|
|
return 0;
|
|
end|
|
|
delimiter ;|
|
|
set sql_log_bin=0;
|
|
insert into t2 (id) values(1),(2),(3);
|
|
delete from t2;
|
|
set sql_log_bin=1;
|
|
#inside SELECT, then inside INSERT
|
|
select insid();
|
|
set sql_log_bin=0;
|
|
insert into t2 (id) values(5),(6),(7);
|
|
delete from t2 where id>=5;
|
|
set sql_log_bin=1;
|
|
insert into t1 select insid();
|
|
select * from t1;
|
|
select * from t2;
|
|
|
|
sync_slave_with_master;
|
|
select * from t1;
|
|
select * from t2;
|
|
|
|
connection master;
|
|
drop table t1, t2;
|
|
drop function insid;
|
|
|
|
sync_slave_with_master;
|