mirror of
https://github.com/MariaDB/server.git
synced 2025-01-18 13:02:28 +01:00
986679a287
The bug was that if the server was running in mixed binlogging mode, and an INSERT DELAYED used some needing-row-based components like UUID(), the server didn't binlog this row-based but statement-based, which thus failed to insert correct data on the slave. This changeset implements that when a delayed_insert thread is created, if the server's global binlog mode is "mixed", that thread will use row-based. This also fixes BUG#20633 "INSERT DELAYED RAND() or @user_var does not replicate statement-based": we don't fix it in statement-based mode (would require bookeeping of rand seeds and user variables used by each row), but at least it will now work in mixed mode (as row-based will be used). We re-enable rpl_switch_stm_row_mixed.test (so BUG#18590 which was about re-enabling this test, will be closed) to test the fixes. Between when it was disabled and now, some good changes to row-based binlogging (no generation of table map events for non-changed tables) induce changes in the test's result file. mysql-test/r/rpl_switch_stm_row_mixed.result: result update. Note that some pieces of binlog are gone, not due to my test but to changes to the row-based binlogging code (non-changed tables don't generate table map binlog events now) done while the test was disabled. mysql-test/t/disabled.def: this test works now mysql-test/t/rpl_switch_stm_row_mixed.test: testing fix to make INSERT DELAYED work in mixed mode sql/sql_insert.cc: In mixed binlogging mode, the delayed_insert system thread now always uses row-based binlogging. This makes replication of INSERT DELAYED VALUES(RAND()) or VALUES(@a) work in mixed mode (it does not in statement-based).
223 lines
7.3 KiB
Text
223 lines
7.3 KiB
Text
-- source include/have_binlog_format_row.inc
|
|
-- source include/master-slave.inc
|
|
|
|
connection master;
|
|
--disable_warnings
|
|
drop database if exists mysqltest1;
|
|
create database mysqltest1;
|
|
--enable_warnings
|
|
use mysqltest1;
|
|
|
|
show global variables like "binlog_format%";
|
|
show session variables like "binlog_format%";
|
|
select @@global.binlog_format, @@session.binlog_format;
|
|
|
|
CREATE TABLE t1 (a varchar(100));
|
|
|
|
prepare stmt1 from 'insert into t1 select concat(UUID(),?)';
|
|
set @string="emergency";
|
|
insert into t1 values("work");
|
|
execute stmt1 using @string;
|
|
deallocate prepare stmt1;
|
|
|
|
prepare stmt1 from 'insert into t1 select ?';
|
|
insert into t1 values(concat(UUID(),"work"));
|
|
execute stmt1 using @string;
|
|
deallocate prepare stmt1;
|
|
|
|
insert into t1 values(concat("for",UUID()));
|
|
insert into t1 select "yesterday";
|
|
|
|
# verify that temp tables prevent a switch to SBR
|
|
create temporary table tmp(a char(3));
|
|
insert into tmp values("see");
|
|
--error ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR
|
|
set binlog_format=statement;
|
|
insert into t1 select * from tmp;
|
|
drop temporary table tmp;
|
|
|
|
# Now we go to SBR
|
|
set binlog_format=statement;
|
|
show global variables like "binlog_format%";
|
|
show session variables like "binlog_format%";
|
|
select @@global.binlog_format, @@session.binlog_format;
|
|
set global binlog_format=statement;
|
|
show global variables like "binlog_format%";
|
|
show session variables like "binlog_format%";
|
|
select @@global.binlog_format, @@session.binlog_format;
|
|
|
|
prepare stmt1 from 'insert into t1 select ?';
|
|
set @string="emergency";
|
|
insert into t1 values("work");
|
|
execute stmt1 using @string;
|
|
deallocate prepare stmt1;
|
|
|
|
prepare stmt1 from 'insert into t1 select ?';
|
|
insert into t1 values("work");
|
|
execute stmt1 using @string;
|
|
deallocate prepare stmt1;
|
|
|
|
insert into t1 values("for");
|
|
insert into t1 select "yesterday";
|
|
|
|
# test SET DEFAULT (=statement at this point of test)
|
|
set binlog_format=default;
|
|
select @@global.binlog_format, @@session.binlog_format;
|
|
# due to cluster it's hard to set back to default
|
|
--error ER_NO_DEFAULT
|
|
set global binlog_format=default;
|
|
select @@global.binlog_format, @@session.binlog_format;
|
|
|
|
prepare stmt1 from 'insert into t1 select ?';
|
|
set @string="emergency";
|
|
insert into t1 values("work");
|
|
execute stmt1 using @string;
|
|
deallocate prepare stmt1;
|
|
|
|
prepare stmt1 from 'insert into t1 select ?';
|
|
insert into t1 values("work");
|
|
execute stmt1 using @string;
|
|
deallocate prepare stmt1;
|
|
|
|
insert into t1 values("for");
|
|
insert into t1 select "yesterday";
|
|
|
|
# and now the mixed mode
|
|
|
|
set binlog_format=mixed;
|
|
select @@global.binlog_format, @@session.binlog_format;
|
|
set global binlog_format=mixed;
|
|
select @@global.binlog_format, @@session.binlog_format;
|
|
|
|
prepare stmt1 from 'insert into t1 select concat(UUID(),?)';
|
|
set @string="emergency";
|
|
insert into t1 values("work");
|
|
execute stmt1 using @string;
|
|
deallocate prepare stmt1;
|
|
|
|
prepare stmt1 from 'insert into t1 select ?';
|
|
insert into t1 values(concat(UUID(),"work"));
|
|
execute stmt1 using @string;
|
|
deallocate prepare stmt1;
|
|
|
|
insert into t1 values(concat("for",UUID()));
|
|
insert into t1 select "yesterday";
|
|
|
|
prepare stmt1 from 'insert into t1 select ?';
|
|
insert into t1 values(concat(UUID(),"work"));
|
|
execute stmt1 using @string;
|
|
deallocate prepare stmt1;
|
|
|
|
insert into t1 values(concat("for",UUID()));
|
|
insert into t1 select "yesterday";
|
|
|
|
# Test of CREATE TABLE SELECT
|
|
|
|
create table t2 select UUID();
|
|
create table t3 select 1 union select UUID();
|
|
create table t4 select * from t1 where 3 in (select 1 union select 2 union select UUID() union select 3);
|
|
create table t5 select * from t1 where 3 in (select 1 union select 2 union select curdate() union select 3);
|
|
# what if UUID() is first:
|
|
insert into t5 select UUID() from t1 where 3 in (select 1 union select 2 union select 3 union select * from t4);
|
|
|
|
# inside a stored procedure (inside a function or trigger won't
|
|
# work)
|
|
|
|
delimiter |;
|
|
create procedure foo()
|
|
begin
|
|
insert into t1 values("work");
|
|
insert into t1 values(concat("for",UUID()));
|
|
insert into t1 select "yesterday";
|
|
end|
|
|
create procedure foo2()
|
|
begin
|
|
insert into t1 values(concat("emergency",UUID()));
|
|
insert into t1 values("work");
|
|
insert into t1 values(concat("for",UUID()));
|
|
set session binlog_format=row; # accepted for stored procs
|
|
insert into t1 values("more work");
|
|
set session binlog_format=mixed;
|
|
end|
|
|
create function foo3() returns bigint unsigned
|
|
begin
|
|
set session binlog_format=row; # rejected for stored funcs
|
|
insert into t1 values("alarm");
|
|
return 100;
|
|
end|
|
|
delimiter ;|
|
|
call foo();
|
|
call foo2();
|
|
|
|
# test that can't SET in a stored function
|
|
--error ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT
|
|
select foo3();
|
|
select * from t1 where a="alarm";
|
|
|
|
# Test that INSERT DELAYED works in mixed mode
|
|
insert delayed into t2 values("delay_1_");
|
|
insert delayed into t2 values(concat("delay_2_",UUID()));
|
|
insert delayed into t2 values("delay_3_"),(concat("delay_4_",UUID())),("delay_5_");
|
|
insert delayed into t2 values("delay_6_");
|
|
sleep 4; # time for the delayed insert to reach disk
|
|
|
|
# If you want to do manual testing of the mixed mode regarding UDFs (not
|
|
# testable automatically as quite platform- and compiler-dependent),
|
|
# you just need to set the variable below to 1, and to
|
|
# "make udf_example.so" in sql/, and to copy sql/udf_example.so to
|
|
# MYSQL_TEST_DIR/lib/mysql.
|
|
let $you_want_to_test_UDF=0;
|
|
if ($you_want_to_test_UDF)
|
|
{
|
|
CREATE FUNCTION metaphon RETURNS STRING SONAME 'udf_example.so';
|
|
prepare stmt1 from 'insert into t1 select metaphon(?)';
|
|
set @string="emergency";
|
|
insert into t1 values("work");
|
|
execute stmt1 using @string;
|
|
deallocate prepare stmt1;
|
|
prepare stmt1 from 'insert into t1 select ?';
|
|
insert into t1 values(metaphon("work"));
|
|
execute stmt1 using @string;
|
|
deallocate prepare stmt1;
|
|
insert into t1 values(metaphon("for"));
|
|
insert into t1 select "yesterday";
|
|
create table t6 select metaphon("for");
|
|
create table t7 select 1 union select metaphon("for");
|
|
create table t8 select * from t1 where 3 in (select 1 union select 2 union select metaphon("for") union select 3);
|
|
create table t9 select * from t1 where 3 in (select 1 union select 2 union select curdate() union select 3);
|
|
}
|
|
|
|
# and now compare:
|
|
|
|
# first check that data on master is sensible
|
|
select count(*) from t1;
|
|
select count(*) from t2;
|
|
select count(*) from t3;
|
|
select count(*) from t4;
|
|
select count(*) from t5;
|
|
if ($you_want_to_test_UDF)
|
|
{
|
|
select count(*) from t6;
|
|
select count(*) from t7;
|
|
select count(*) from t8;
|
|
select count(*) from t9;
|
|
}
|
|
|
|
--replace_column 2 # 5 #
|
|
--replace_regex /table_id: [0-9]+/table_id: #/
|
|
show binlog events from 102;
|
|
sync_slave_with_master;
|
|
# as we're using UUID we don't SELECT but use "diff" like in rpl_row_UUID
|
|
--exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info mysqltest1 > $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_master.sql
|
|
--exec $MYSQL_DUMP_SLAVE --compact --order-by-primary --skip-extended-insert --no-create-info mysqltest1 > $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_slave.sql
|
|
|
|
connection master;
|
|
drop database mysqltest1;
|
|
sync_slave_with_master;
|
|
|
|
# Let's compare. Note: If they match test will pass, if they do not match
|
|
# the test will show that the diff statement failed and not reject file
|
|
# will be created. You will need to go to the mysql-test dir and diff
|
|
# the files your self to see what is not matching
|
|
|
|
--exec diff $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_master.sql $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_slave.sql;
|