Commit 81a80049 authored by unknown's avatar unknown

* Mixed replication mode * :

1) Fix for BUG#19630 "stored function inserting into two auto_increment breaks
statement-based binlog":
a stored function inserting into two such tables may fail to replicate
(inserting wrong data in the slave's copy of the second table) if the slave's
second table had an internal auto_increment counter different from master's.
Because the auto_increment value autogenerated by master for the 2nd table
does not go into binlog, only the first does, so the slave lacks information.
To fix this, if running in mixed binlogging mode, if the stored function or
trigger plans to update two different tables both having auto_increment
columns, we switch to row-based for the whole function.
We don't have a simple solution for statement-based binlogging mode, there
the bug remains and will be documented as a known problem.
Re-enabling rpl_switch_stm_row_mixed.
2) Fix for BUG#20630 "Mixed binlogging mode does not work with stored
functions, triggers, views", which was a documented limitation (in mixed
mode, we didn't detect that a stored function's execution needed row-based
binlogging (due to some UUID() call for example); same for
triggers, same for views (a view created from a SELECT UUID(), and doing
INSERT INTO sometable SELECT theview; would not replicate row-based).
This is implemented by, after parsing a routine's body, remembering in sp_head
that this routine needs row-based binlogging. Then when this routine is used,
the caller is marked to require row-based binlogging too.
Same for views: when we parse a view and detect that its SELECT needs
row-based binary logging, we mark the calling LEX as such.
3) Fix for BUG#20499 "mixed mode with temporary table breaks binlog":
a temporary table containing e.g. UUID has its changes not binlogged,
so any query updating a permanent table with data from the temporary table
will run wrongly on slave. Solution: in mixed mode we don't switch back
from row-based to statement-based when there exists temporary tables.
4) Attempt to test mysqlbinlog on a binlog generated by mysqlbinlog;
impossible due to BUG#11312 and BUG#20329, but test is in place for when
they are fixed.


mysql-test/r/rpl_switch_stm_row_mixed.result:
  testing BUG#19630 "stored function inserting into two auto_increment breaks
  statement-based binlog",
  testing BUG#20930 "Mixed binlogging mode does not work with stored functions,
  triggers, views.
  testing BUG#20499 "mixed mode with temporary table breaks binlog".
  I have carefully checked this big result file, it is correct.
mysql-test/t/disabled.def:
  re-enabling test
mysql-test/t/rpl_switch_stm_row_mixed.test:
  Test for BUG#19630 "stored function inserting into two auto_increment breaks
  statement-based binlog":
  we test that it goes row-based, but only when needed;
  without the bugfix, master and slave's data differed.
  Test for BUG#20499 "mixed mode with temporary table breaks binlog":
  without the bugfix, slave had 2 rows, not 3.
  Test for BUG#20930 "Mixed binlogging mode does not work with stored
  functions, triggers, views".
  Making strings used more different, for easier tracking of "by which routine
  was this binlog line generated".
  Towards the end, an attempt to test mysqlbinlog on a binlog generated by
  the mixed mode; attempt failed because of BUG#11312 and BUG#20929.
sql/item_create.cc:
  fix for build without row-based replication
sql/set_var.cc:
  cosmetic: in_sub_stmt is exactly meant to say if we are in stored
  function/trigger, so better use it.
sql/sp.cc:
  When a routine adds its tables to the top statement's tables, if this routine
  needs row-based binlogging, mark the entire top statement as well.
  Same for triggers.
  Needed for making the mixed replication mode work with stored functions
  and triggers.
sql/sp_head.cc:
  new enum value for sp_head::m_flags, remembers if, when parsing the 
  routine, we found at least one element (UUID(), UDF) requiring row-based
  binlogging.
sql/sp_head.h:
  new enum value for sp_head::m_flags (see sp_head.cc).
  An utility method, intended for attributes of a routine which need
  to propagate upwards to the caller; so far only used for binlogging
  information, but open to any other attribute.
sql/sql_base.cc:
  For BUG#19630 "stored function inserting into two auto_increment
  breaks statement-based binlog":
  When we come to locking tables, we have collected all tables used by
  functions, views and triggers, we detect if we're going to update two tables
  having auto_increment columns. If yes, statement-based binlogging won't work
  (Intvar_log_event records only one insert_id) so, if in mixed binlogging
  mode, switch to row-based.
  For making mixed mode work with stored functions using UUID/UDF:
  when we come to locking tables, we have parsed the whole body so know if
  some elements need row-based. Generation of row-based binlog events
  depends on locked tables, so this is the good place to decide of the binlog
  format.
sql/sql_class.h:
  Fix for BUG#20499 "mixed mode with temporary table breaks binlog".
  Making mixed mode work with stored functions/triggers: don't reset
  back to statement-based if in executing a stored function/trigger.
sql/sql_lex.cc:
  fix for build without row-based replication.
  binlog_row_based_if_mixed moves from st_lex to Query_tables_list, because
  that boolean should not be affected when a SELECT reads the INFORMATION_SCHEMA
  and thus implicitely parses a view or routine's body: this body may
  contain needing-row-based components like UUID() but the SELECT on
  INFORMATION_SCHEMA should not be affected by that and should not use
  row-based; as Query_tables_list is backed-up/reset/restored when parsing
  the view/routine's body, so does binlog_row_based_if_mixed and the
  top SELECT is not affected.
sql/sql_lex.h:
  fix for build without row-based replication.
  binlog_row_based_if_mixed moves from st_lex to Query_tables_list
  (see sql_lex.cc)
sql/sql_parse.cc:
  For the mixed mode to work with stored functions using UUID and UDF, we need
  to move the switch-back-from-row-to-statement out of
  mysql_execute_command() (which is executed for each statement, causing
  the binlogging mode to change in the middle of the function, which would
  not work)
  The switch to row-based is now done in lock_tables(), no need to keep it
  in mysql_execute_command(); in lock_tables() we also switch back from 
  row-based to statement-based (so in a stored procedure, all statements
  have their binlogging mode). We must however keep a resetting in
  mysql_reset_thd_for_next_command() as e.g. CREATE PROCEDURE does not call
  lock_tables().
sql/sql_view.cc:
  When a view's body needs row-based binlogging (e.g. the view is created
  from SELECT UUID()), propagate this fact to the top st_lex.
sql/sql_yacc.yy:
  use TRUE instead of 1, for binlog_row_based_if_mixed.
parent debae050
......@@ -18,18 +18,18 @@ select @@global.binlog_format, @@session.binlog_format;
ROW ROW
CREATE TABLE t1 (a varchar(100));
prepare stmt1 from 'insert into t1 select concat(UUID(),?)';
set @string="emergency";
insert into t1 values("work");
set @string="emergency_1_";
insert into t1 values("work_2_");
execute stmt1 using @string;
deallocate prepare stmt1;
prepare stmt1 from 'insert into t1 select ?';
insert into t1 values(concat(UUID(),"work"));
insert into t1 values(concat(UUID(),"work_3_"));
execute stmt1 using @string;
deallocate prepare stmt1;
insert into t1 values(concat("for",UUID()));
insert into t1 select "yesterday";
create temporary table tmp(a char(3));
insert into tmp values("see");
insert into t1 values(concat("for_4_",UUID()));
insert into t1 select "yesterday_5_";
create temporary table tmp(a char(100));
insert into tmp values("see_6_");
set binlog_format=statement;
ERROR HY000: Cannot switch out of the row-based binary log format when the session has open temporary tables
insert into t1 select * from tmp;
......@@ -55,16 +55,16 @@ select @@global.binlog_format, @@session.binlog_format;
@@global.binlog_format @@session.binlog_format
STATEMENT STATEMENT
prepare stmt1 from 'insert into t1 select ?';
set @string="emergency";
insert into t1 values("work");
set @string="emergency_7_";
insert into t1 values("work_8_");
execute stmt1 using @string;
deallocate prepare stmt1;
prepare stmt1 from 'insert into t1 select ?';
insert into t1 values("work");
insert into t1 values("work_9_");
execute stmt1 using @string;
deallocate prepare stmt1;
insert into t1 values("for");
insert into t1 select "yesterday";
insert into t1 values("for_10_");
insert into t1 select "yesterday_11_";
set binlog_format=default;
select @@global.binlog_format, @@session.binlog_format;
@@global.binlog_format @@session.binlog_format
......@@ -75,16 +75,16 @@ select @@global.binlog_format, @@session.binlog_format;
@@global.binlog_format @@session.binlog_format
STATEMENT STATEMENT
prepare stmt1 from 'insert into t1 select ?';
set @string="emergency";
insert into t1 values("work");
set @string="emergency_12_";
insert into t1 values("work_13_");
execute stmt1 using @string;
deallocate prepare stmt1;
prepare stmt1 from 'insert into t1 select ?';
insert into t1 values("work");
insert into t1 values("work_14_");
execute stmt1 using @string;
deallocate prepare stmt1;
insert into t1 values("for");
insert into t1 select "yesterday";
insert into t1 values("for_15_");
insert into t1 select "yesterday_16_";
set binlog_format=mixed;
select @@global.binlog_format, @@session.binlog_format;
@@global.binlog_format @@session.binlog_format
......@@ -94,40 +94,40 @@ select @@global.binlog_format, @@session.binlog_format;
@@global.binlog_format @@session.binlog_format
MIXED MIXED
prepare stmt1 from 'insert into t1 select concat(UUID(),?)';
set @string="emergency";
insert into t1 values("work");
set @string="emergency_17_";
insert into t1 values("work_18_");
execute stmt1 using @string;
deallocate prepare stmt1;
prepare stmt1 from 'insert into t1 select ?';
insert into t1 values(concat(UUID(),"work"));
insert into t1 values(concat(UUID(),"work_19_"));
execute stmt1 using @string;
deallocate prepare stmt1;
insert into t1 values(concat("for",UUID()));
insert into t1 select "yesterday";
insert into t1 values(concat("for_20_",UUID()));
insert into t1 select "yesterday_21_";
prepare stmt1 from 'insert into t1 select ?';
insert into t1 values(concat(UUID(),"work"));
insert into t1 values(concat(UUID(),"work_22_"));
execute stmt1 using @string;
deallocate prepare stmt1;
insert into t1 values(concat("for",UUID()));
insert into t1 select "yesterday";
create table t2 select UUID();
insert into t1 values(concat("for_23_",UUID()));
insert into t1 select "yesterday_24_";
create table t2 select rpad(UUID(),100,' ');
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);
insert into t5 select UUID() from t1 where 3 in (select 1 union select 2 union select 3 union select * from t4);
create procedure foo()
begin
insert into t1 values("work");
insert into t1 values(concat("for",UUID()));
insert into t1 select "yesterday";
insert into t1 values("work_25_");
insert into t1 values(concat("for_26_",UUID()));
insert into t1 select "yesterday_27_";
end|
create procedure foo2()
begin
insert into t1 values(concat("emergency",UUID()));
insert into t1 values("work");
insert into t1 values(concat("for",UUID()));
insert into t1 values(concat("emergency_28_",UUID()));
insert into t1 values("work_29_");
insert into t1 values(concat("for_30_",UUID()));
set session binlog_format=row; # accepted for stored procs
insert into t1 values("more work");
insert into t1 values("more work_31_");
set session binlog_format=mixed;
end|
create function foo3() returns bigint unsigned
......@@ -136,32 +136,221 @@ set session binlog_format=row; # rejected for stored funcs
insert into t1 values("alarm");
return 100;
end|
create procedure foo4(x varchar(100))
begin
insert into t1 values(concat("work_250_",x));
insert into t1 select "yesterday_270_";
end|
call foo();
call foo2();
call foo4("hello");
call foo4(UUID());
call foo4("world");
select foo3();
ERROR HY000: Cannot change the binary logging format inside a stored function or trigger
select * from t1 where a="alarm";
a
drop function foo3;
create function foo3() returns bigint unsigned
begin
insert into t1 values("foo3_32_");
call foo();
return 100;
end|
insert into t2 select foo3();
prepare stmt1 from 'insert into t2 select foo3()';
execute stmt1;
execute stmt1;
deallocate prepare stmt1;
create function foo4() returns bigint unsigned
begin
insert into t2 select foo3();
return 100;
end|
select foo4();
foo4()
100
prepare stmt1 from 'select foo4()';
execute stmt1;
foo4()
100
execute stmt1;
foo4()
100
deallocate prepare stmt1;
create function foo5() returns bigint unsigned
begin
insert into t2 select UUID();
return 100;
end|
select foo5();
foo5()
100
prepare stmt1 from 'select foo5()';
execute stmt1;
foo5()
100
execute stmt1;
foo5()
100
deallocate prepare stmt1;
create function foo6(x varchar(100)) returns bigint unsigned
begin
insert into t2 select x;
return 100;
end|
select foo6("foo6_1_");
foo6("foo6_1_")
100
select foo6(concat("foo6_2_",UUID()));
foo6(concat("foo6_2_",UUID()))
100
prepare stmt1 from 'select foo6(concat("foo6_3_",UUID()))';
execute stmt1;
foo6(concat("foo6_3_",UUID()))
100
execute stmt1;
foo6(concat("foo6_3_",UUID()))
100
deallocate prepare stmt1;
create view v1 as select uuid();
create table t11 (data varchar(255));
insert into t11 select * from v1;
insert into t11 select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='mysqltest1' and TABLE_NAME IN ('v1','t11');
prepare stmt1 from "insert into t11 select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='mysqltest1' and TABLE_NAME IN ('v1','t11')";
execute stmt1;
execute stmt1;
deallocate prepare stmt1;
create trigger t11_bi before insert on t11 for each row
begin
set NEW.data = concat(NEW.data,UUID());
end|
insert into t11 values("try_560_");
create table t20 select * from t1;
create table t21 select * from t2;
create table t22 select * from t3;
drop table t1,t2,t3;
create table t1 (a int primary key auto_increment, b varchar(100));
create table t2 (a int primary key auto_increment, b varchar(100));
create table t3 (b varchar(100));
create function f (x varchar(100)) returns int deterministic
begin
insert into t1 values(null,x);
insert into t2 values(null,x);
return 1;
end|
select f("try_41_");
f("try_41_")
1
use mysqltest1;
insert into t2 values(2,null),(3,null),(4,null);
delete from t2 where a>=2;
select f("try_42_");
f("try_42_")
1
insert into t2 values(3,null),(4,null);
delete from t2 where a>=3;
prepare stmt1 from 'select f(?)';
set @string="try_43_";
insert into t1 values(null,"try_44_");
execute stmt1 using @string;
f(?)
1
deallocate prepare stmt1;
create table t12 select * from t1;
drop table t1;
create table t1 (a int, b varchar(100), key(a));
select f("try_45_");
f("try_45_")
1
create table t13 select * from t1;
drop table t1;
create table t1 (a int primary key auto_increment, b varchar(100));
drop function f;
truncate table t2;
create function f1 (x varchar(100)) returns int deterministic
begin
insert into t1 values(null,x);
return 1;
end|
create function f2 (x varchar(100)) returns int deterministic
begin
insert into t2 values(null,x);
return 1;
end|
select f1("try_46_"),f2("try_47_");
f1("try_46_") f2("try_47_")
1 1
insert into t2 values(2,null),(3,null),(4,null);
delete from t2 where a>=2;
select f1("try_48_"),f2("try_49_");
f1("try_48_") f2("try_49_")
1 1
insert into t3 values(concat("try_50_",f1("try_51_"),f2("try_52_")));
drop function f2;
create function f2 (x varchar(100)) returns int deterministic
begin
declare y int;
insert into t1 values(null,x);
set y = (select count(*) from t2);
return y;
end|
select f1("try_53_"),f2("try_54_");
f1("try_53_") f2("try_54_")
1 3
drop function f2;
create trigger t1_bi before insert on t1 for each row
begin
insert into t2 values(null,"try_55_");
end|
insert into t1 values(null,"try_56_");
alter table t1 modify a int, drop primary key;
insert into t1 values(null,"try_57_");
CREATE TEMPORARY TABLE t15 SELECT UUID();
create table t16 like t15;
INSERT INTO t16 SELECT * FROM t15;
insert into t16 values("try_65_");
drop table t15;
insert into t16 values("try_66_");
select count(*) from t1;
count(*)
36
7
select count(*) from t2;
count(*)
1
5
select count(*) from t3;
count(*)
2
1
select count(*) from t4;
count(*)
29
select count(*) from t5;
count(*)
58
select count(*) from t11;
count(*)
8
select count(*) from t20;
count(*)
66
select count(*) from t21;
count(*)
14
select count(*) from t22;
count(*)
2
select count(*) from t12;
count(*)
4
select count(*) from t13;
count(*)
1
select count(*) from t16;
count(*)
3
show binlog events from 102;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # drop database if exists mysqltest1
master-bin.000001 # Table_map 1 # table_id: # (mysql.proc)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # create database mysqltest1
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE TABLE t1 (a varchar(100))
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
......@@ -178,45 +367,41 @@ master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work")
master-bin.000001 # User var 1 # @`string`=_latin1 0x656D657267656E6379 COLLATE latin1_swedish_ci
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work_8_")
master-bin.000001 # User var 1 # @`string`=_latin1 0x656D657267656E63795F375F COLLATE latin1_swedish_ci
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select @'string'
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work")
master-bin.000001 # User var 1 # @`string`=_latin1 0x656D657267656E6379 COLLATE latin1_swedish_ci
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work_9_")
master-bin.000001 # User var 1 # @`string`=_latin1 0x656D657267656E63795F375F COLLATE latin1_swedish_ci
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select @'string'
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("for")
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday"
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work")
master-bin.000001 # User var 1 # @`string`=_latin1 0x656D657267656E6379 COLLATE latin1_swedish_ci
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("for_10_")
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday_11_"
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work_13_")
master-bin.000001 # User var 1 # @`string`=_latin1 0x656D657267656E63795F31325F COLLATE latin1_swedish_ci
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select @'string'
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work")
master-bin.000001 # User var 1 # @`string`=_latin1 0x656D657267656E6379 COLLATE latin1_swedish_ci
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work_14_")
master-bin.000001 # User var 1 # @`string`=_latin1 0x656D657267656E63795F31325F COLLATE latin1_swedish_ci
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select @'string'
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("for")
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday"
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work")
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("for_15_")
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday_16_"
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work_18_")
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # User var 1 # @`string`=_latin1 0x656D657267656E6379 COLLATE latin1_swedish_ci
master-bin.000001 # User var 1 # @`string`=_latin1 0x656D657267656E63795F31375F COLLATE latin1_swedish_ci
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select @'string'
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday"
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday_21_"
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # User var 1 # @`string`=_latin1 0x656D657267656E6379 COLLATE latin1_swedish_ci
master-bin.000001 # User var 1 # @`string`=_latin1 0x656D657267656E63795F31375F COLLATE latin1_swedish_ci
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select @'string'
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday"
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday_24_"
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE TABLE `t2` (
`UUID()` varchar(36) CHARACTER SET utf8 NOT NULL DEFAULT ''
`rpad(UUID(),100,' ')` varchar(100) CHARACTER SET utf8 NOT NULL DEFAULT ''
)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
......@@ -239,17 +424,17 @@ master-bin.000001 # Write_rows 1 # table_id: #
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo()
begin
insert into t1 values("work");
insert into t1 values(concat("for",UUID()));
insert into t1 select "yesterday";
insert into t1 values("work_25_");
insert into t1 values(concat("for_26_",UUID()));
insert into t1 select "yesterday_27_";
end
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo2()
begin
insert into t1 values(concat("emergency",UUID()));
insert into t1 values("work");
insert into t1 values(concat("for",UUID()));
insert into t1 values(concat("emergency_28_",UUID()));
insert into t1 values("work_29_");
insert into t1 values(concat("for_30_",UUID()));
set session binlog_format=row; # accepted for stored procs
insert into t1 values("more work");
insert into t1 values("more work_31_");
set session binlog_format=mixed;
end
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function foo3() returns bigint unsigned
......@@ -258,15 +443,200 @@ set session binlog_format=row; # rejected for stored funcs
insert into t1 values("alarm");
return 100;
end
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work")
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` procedure foo4(x varchar(100))
begin
insert into t1 values(concat("work_250_",x));
insert into t1 select "yesterday_270_";
end
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work_25_")
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday_27_"
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work_29_")
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday"
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values("work")
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values(concat("work_250_", NAME_CONST('x',...
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday_270_"
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values(concat("work_250_", NAME_CONST('x',...
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday_270_"
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values(concat("work_250_", NAME_CONST('x',...
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 select "yesterday_270_"
master-bin.000001 # Query 1 # use `mysqltest1`; drop function foo3
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function foo3() returns bigint unsigned
begin
insert into t1 values("foo3_32_");
call foo();
return 100;
end
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: #
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: #
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: #
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function foo4() returns bigint unsigned
begin
insert into t2 select foo3();
return 100;
end
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: #
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: #
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: #
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function foo5() returns bigint unsigned
begin
insert into t2 select UUID();
return 100;
end
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function foo6(x varchar(100)) returns bigint unsigned
begin
insert into t2 select x;
return 100;
end
master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `foo6`(_latin1'foo6_1_')
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `v1` AS select uuid()
master-bin.000001 # Query 1 # use `mysqltest1`; create table t11 (data varchar(255))
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t11)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t11 select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='mysqltest1' and TABLE_NAME IN ('v1','t11')
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t11 select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='mysqltest1' and TABLE_NAME IN ('v1','t11')
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t11 select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='mysqltest1' and TABLE_NAME IN ('v1','t11')
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` trigger t11_bi before insert on t11 for each row
begin
set NEW.data = concat(NEW.data,UUID());
end
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t11)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; create table t20 select * from t1
master-bin.000001 # Query 1 # use `mysqltest1`; create table t21 select * from t2
master-bin.000001 # Query 1 # use `mysqltest1`; create table t22 select * from t3
master-bin.000001 # Query 1 # use `mysqltest1`; drop table t1,t2,t3
master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a int primary key auto_increment, b varchar(100))
master-bin.000001 # Query 1 # use `mysqltest1`; create table t2 (a int primary key auto_increment, b varchar(100))
master-bin.000001 # Query 1 # use `mysqltest1`; create table t3 (b varchar(100))
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function f (x varchar(100)) returns int deterministic
begin
insert into t1 values(null,x);
insert into t2 values(null,x);
return 1;
end
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: #
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: #
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Intvar 1 # INSERT_ID=3
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values(null,"try_44_")
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Write_rows 1 # table_id: #
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; create table t12 select * from t1
master-bin.000001 # Query 1 # use `mysqltest1`; drop table t1
master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a int, b varchar(100), key(a))
master-bin.000001 # Intvar 1 # INSERT_ID=4
master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `f`(_latin1'try_45_')
master-bin.000001 # Query 1 # use `mysqltest1`; create table t13 select * from t1
master-bin.000001 # Query 1 # use `mysqltest1`; drop table t1
master-bin.000001 # Query 1 # use `mysqltest1`; create table t1 (a int primary key auto_increment, b varchar(100))
master-bin.000001 # Query 1 # use `mysqltest1`; drop function f
master-bin.000001 # Query 1 # use `mysqltest1`; truncate table t2
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function f1 (x varchar(100)) returns int deterministic
begin
insert into t1 values(null,x);
return 1;
end
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function f2 (x varchar(100)) returns int deterministic
begin
insert into t2 values(null,x);
return 1;
end
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Write_rows 1 # table_id: #
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Write_rows 1 # table_id: #
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t3)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Write_rows 1 # table_id: #
master-bin.000001 # Write_rows 1 # table_id: #
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; drop function f2
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` function f2 (x varchar(100)) returns int deterministic
begin
declare y int;
insert into t1 values(null,x);
set y = (select count(*) from t2);
return y;
end
master-bin.000001 # Intvar 1 # INSERT_ID=4
master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `f1`(_latin1'try_53_')
master-bin.000001 # Intvar 1 # INSERT_ID=5
master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `f2`(_latin1'try_54_')
master-bin.000001 # Query 1 # use `mysqltest1`; drop function f2
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` trigger t1_bi before insert on t1 for each row
begin
insert into t2 values(null,"try_55_");
end
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t1)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t2)
master-bin.000001 # Write_rows 1 # table_id: #
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; alter table t1 modify a int, drop primary key
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values(null,"try_57_")
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE TEMPORARY TABLE `t15` (
`UUID()` varchar(36) CHARACTER SET utf8 NOT NULL DEFAULT ''
)
master-bin.000001 # Query 1 # use `mysqltest1`; COMMIT
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE TABLE `t16` (
`UUID()` varchar(36) CHARACTER SET utf8 NOT NULL DEFAULT ''
)
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t16)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Table_map 1 # table_id: # (mysqltest1.t16)
master-bin.000001 # Write_rows 1 # table_id: # flags: STMT_END_F
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t16 values("try_66_")
drop database mysqltest1;
......@@ -32,7 +32,6 @@ rpl_ndb_ddl : BUG#18946 result file needs update + test needs to ch
rpl_ndb_innodb2ndb : Bug #19710 Cluster replication to partition table fails on DELETE FROM statement
#rpl_ndb_log : BUG#18947 2006-03-21 tomas CRBR: order in binlog of create table and insert (on different table) not determ
rpl_ndb_myisam2ndb : Bug #19710 Cluster replication to partition table fails on DELETE FROM statement
rpl_switch_stm_row_mixed : BUG#18590 2006-03-28 brian
rpl_row_blob_innodb : BUG#18980 2006-04-10 kent Test fails randomly
rpl_row_func003 : BUG#19074 2006-13-04 andrei test failed
rpl_sp : BUG#16456 2006-02-16 jmiller
......
......@@ -15,22 +15,22 @@ 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");
set @string="emergency_1_";
insert into t1 values("work_2_");
execute stmt1 using @string;
deallocate prepare stmt1;
prepare stmt1 from 'insert into t1 select ?';
insert into t1 values(concat(UUID(),"work"));
insert into t1 values(concat(UUID(),"work_3_"));
execute stmt1 using @string;
deallocate prepare stmt1;
insert into t1 values(concat("for",UUID()));
insert into t1 select "yesterday";
insert into t1 values(concat("for_4_",UUID()));
insert into t1 select "yesterday_5_";
# verify that temp tables prevent a switch to SBR
create temporary table tmp(a char(3));
insert into tmp values("see");
create temporary table tmp(a char(100));
insert into tmp values("see_6_");
--error ER_TEMP_TABLE_PREVENTS_SWITCH_OUT_OF_RBR
set binlog_format=statement;
insert into t1 select * from tmp;
......@@ -47,18 +47,18 @@ 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");
set @string="emergency_7_";
insert into t1 values("work_8_");
execute stmt1 using @string;
deallocate prepare stmt1;
prepare stmt1 from 'insert into t1 select ?';
insert into t1 values("work");
insert into t1 values("work_9_");
execute stmt1 using @string;
deallocate prepare stmt1;
insert into t1 values("for");
insert into t1 select "yesterday";
insert into t1 values("for_10_");
insert into t1 select "yesterday_11_";
# test SET DEFAULT (=statement at this point of test)
set binlog_format=default;
......@@ -69,18 +69,18 @@ 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");
set @string="emergency_12_";
insert into t1 values("work_13_");
execute stmt1 using @string;
deallocate prepare stmt1;
prepare stmt1 from 'insert into t1 select ?';
insert into t1 values("work");
insert into t1 values("work_14_");
execute stmt1 using @string;
deallocate prepare stmt1;
insert into t1 values("for");
insert into t1 select "yesterday";
insert into t1 values("for_15_");
insert into t1 select "yesterday_16_";
# and now the mixed mode
......@@ -90,53 +90,52 @@ 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");
set @string="emergency_17_";
insert into t1 values("work_18_");
execute stmt1 using @string;
deallocate prepare stmt1;
prepare stmt1 from 'insert into t1 select ?';
insert into t1 values(concat(UUID(),"work"));
insert into t1 values(concat(UUID(),"work_19_"));
execute stmt1 using @string;
deallocate prepare stmt1;
insert into t1 values(concat("for",UUID()));
insert into t1 select "yesterday";
insert into t1 values(concat("for_20_",UUID()));
insert into t1 select "yesterday_21_";
prepare stmt1 from 'insert into t1 select ?';
insert into t1 values(concat(UUID(),"work"));
insert into t1 values(concat(UUID(),"work_22_"));
execute stmt1 using @string;
deallocate prepare stmt1;
insert into t1 values(concat("for",UUID()));
insert into t1 select "yesterday";
insert into t1 values(concat("for_23_",UUID()));
insert into t1 select "yesterday_24_";
# Test of CREATE TABLE SELECT
create table t2 select UUID();
create table t2 select rpad(UUID(),100,' ');
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)
# inside a stored procedure
delimiter |;
create procedure foo()
begin
insert into t1 values("work");
insert into t1 values(concat("for",UUID()));
insert into t1 select "yesterday";
insert into t1 values("work_25_");
insert into t1 values(concat("for_26_",UUID()));
insert into t1 select "yesterday_27_";
end|
create procedure foo2()
begin
insert into t1 values(concat("emergency",UUID()));
insert into t1 values("work");
insert into t1 values(concat("for",UUID()));
insert into t1 values(concat("emergency_28_",UUID()));
insert into t1 values("work_29_");
insert into t1 values(concat("for_30_",UUID()));
set session binlog_format=row; # accepted for stored procs
insert into t1 values("more work");
insert into t1 values("more work_31_");
set session binlog_format=mixed;
end|
create function foo3() returns bigint unsigned
......@@ -145,15 +144,116 @@ begin
insert into t1 values("alarm");
return 100;
end|
create procedure foo4(x varchar(100))
begin
insert into t1 values(concat("work_250_",x));
insert into t1 select "yesterday_270_";
end|
delimiter ;|
call foo();
call foo2();
call foo4("hello");
call foo4(UUID());
call foo4("world");
# 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";
# Tests of stored functions/triggers/views for BUG#20930 "Mixed
# binlogging mode does not work with stored functions, triggers,
# views"
# Function which calls procedure
drop function foo3;
delimiter |;
create function foo3() returns bigint unsigned
begin
insert into t1 values("foo3_32_");
call foo();
return 100;
end|
delimiter ;|
insert into t2 select foo3();
prepare stmt1 from 'insert into t2 select foo3()';
execute stmt1;
execute stmt1;
deallocate prepare stmt1;
# Test if stored function calls stored function which calls procedure
# which requires row-based.
delimiter |;
create function foo4() returns bigint unsigned
begin
insert into t2 select foo3();
return 100;
end|
delimiter ;|
select foo4();
prepare stmt1 from 'select foo4()';
execute stmt1;
execute stmt1;
deallocate prepare stmt1;
# A simple stored function
delimiter |;
create function foo5() returns bigint unsigned
begin
insert into t2 select UUID();
return 100;
end|
delimiter ;|
select foo5();
prepare stmt1 from 'select foo5()';
execute stmt1;
execute stmt1;
deallocate prepare stmt1;
# A simple stored function where UUID() is in the argument
delimiter |;
create function foo6(x varchar(100)) returns bigint unsigned
begin
insert into t2 select x;
return 100;
end|
delimiter ;|
select foo6("foo6_1_");
select foo6(concat("foo6_2_",UUID()));
prepare stmt1 from 'select foo6(concat("foo6_3_",UUID()))';
execute stmt1;
execute stmt1;
deallocate prepare stmt1;
# Test of views using UUID()
create view v1 as select uuid();
create table t11 (data varchar(255));
insert into t11 select * from v1;
# Test of querying INFORMATION_SCHEMA which parses the view's body,
# to verify that it binlogs statement-based (is not polluted by
# the parsing of the view's body).
insert into t11 select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='mysqltest1' and TABLE_NAME IN ('v1','t11');
prepare stmt1 from "insert into t11 select TABLE_NAME from INFORMATION_SCHEMA.TABLES where TABLE_SCHEMA='mysqltest1' and TABLE_NAME IN ('v1','t11')";
execute stmt1;
execute stmt1;
deallocate prepare stmt1;
# Test of triggers with UUID()
delimiter |;
create trigger t11_bi before insert on t11 for each row
begin
set NEW.data = concat(NEW.data,UUID());
end|
delimiter ;|
insert into t11 values("try_560_");
# 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
......@@ -164,30 +264,182 @@ 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");
set @string="emergency_133_";
insert into t1 values("work_134_");
execute stmt1 using @string;
deallocate prepare stmt1;
prepare stmt1 from 'insert into t1 select ?';
insert into t1 values(metaphon("work"));
insert into t1 values(metaphon("work_135_"));
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);
insert into t1 values(metaphon("for_136_"));
insert into t1 select "yesterday_137_";
create table t6 select metaphon("for_138_");
create table t7 select 1 union select metaphon("for_139_");
create table t8 select * from t1 where 3 in (select 1 union select 2 union select metaphon("for_140_") union select 3);
create table t9 select * from t1 where 3 in (select 1 union select 2 union select curdate() union select 3);
}
create table t20 select * from t1; # save for comparing later
create table t21 select * from t2;
create table t22 select * from t3;
drop table t1,t2,t3;
# This tests the fix to
# BUG#19630 stored function inserting into two auto_increment breaks statement-based binlog
# We verify that under the mixed binlog mode, a stored function
# modifying at least two tables having an auto_increment column,
# is binlogged row-based. Indeed in statement-based binlogging,
# only the auto_increment value generated for the first table
# is recorded in the binlog, the value generated for the 2nd table
# lacking.
create table t1 (a int primary key auto_increment, b varchar(100));
create table t2 (a int primary key auto_increment, b varchar(100));
create table t3 (b varchar(100));
delimiter |;
create function f (x varchar(100)) returns int deterministic
begin
insert into t1 values(null,x);
insert into t2 values(null,x);
return 1;
end|
delimiter ;|
select f("try_41_");
# Two operations which compensate each other except that their net
# effect is that they advance the auto_increment counter of t2 on slave:
sync_slave_with_master;
use mysqltest1;
insert into t2 values(2,null),(3,null),(4,null);
delete from t2 where a>=2;
connection master;
# this is the call which didn't replicate well
select f("try_42_");
sync_slave_with_master;
# now use prepared statement and test again, just to see that the RBB
# mode isn't set at PREPARE but at EXECUTE.
insert into t2 values(3,null),(4,null);
delete from t2 where a>=3;
connection master;
prepare stmt1 from 'select f(?)';
set @string="try_43_";
insert into t1 values(null,"try_44_"); # should be SBB
execute stmt1 using @string; # should be RBB
deallocate prepare stmt1;
sync_slave_with_master;
# verify that if only one table has auto_inc, it does not trigger RBB
# (we'll check in binlog further below)
connection master;
create table t12 select * from t1; # save for comparing later
drop table t1;
create table t1 (a int, b varchar(100), key(a));
select f("try_45_");
# restore table's key
create table t13 select * from t1;
drop table t1;
create table t1 (a int primary key auto_increment, b varchar(100));
# now test if it's two functions, each of them inserts in one table
drop function f;
# Manifestation of BUG#20341! re-enable this line after merging fix
# for that bug
#create table t14 select * from t2;
truncate table t2;
delimiter |;
create function f1 (x varchar(100)) returns int deterministic
begin
insert into t1 values(null,x);
return 1;
end|
create function f2 (x varchar(100)) returns int deterministic
begin
insert into t2 values(null,x);
return 1;
end|
delimiter ;|
select f1("try_46_"),f2("try_47_");
sync_slave_with_master;
insert into t2 values(2,null),(3,null),(4,null);
delete from t2 where a>=2;
connection master;
# Test with SELECT and INSERT
select f1("try_48_"),f2("try_49_");
insert into t3 values(concat("try_50_",f1("try_51_"),f2("try_52_")));
sync_slave_with_master;
# verify that if f2 does only read on an auto_inc table, this does not
# switch to RBB
connection master;
drop function f2;
delimiter |;
create function f2 (x varchar(100)) returns int deterministic
begin
declare y int;
insert into t1 values(null,x);
set y = (select count(*) from t2);
return y;
end|
delimiter ;|
select f1("try_53_"),f2("try_54_");
sync_slave_with_master;
# And now, a normal statement with a trigger (no stored functions)
connection master;
drop function f2;
delimiter |;
create trigger t1_bi before insert on t1 for each row
begin
insert into t2 values(null,"try_55_");
end|
delimiter ;|
insert into t1 values(null,"try_56_");
# and now remove one auto_increment and verify SBB
alter table t1 modify a int, drop primary key;
insert into t1 values(null,"try_57_");
sync_slave_with_master;
# Test for BUG#20499 "mixed mode with temporary table breaks binlog"
# Slave used to have only 2 rows instead of 3.
connection master;
CREATE TEMPORARY TABLE t15 SELECT UUID();
create table t16 like t15;
INSERT INTO t16 SELECT * FROM t15;
# we'll verify that this one is done RBB
insert into t16 values("try_65_");
drop table t15;
# we'll verify that this one is done SBB
insert into t16 values("try_66_");
sync_slave_with_master;
# and now compare:
connection master;
# 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;
select count(*) from t11;
select count(*) from t20;
select count(*) from t21;
select count(*) from t22;
select count(*) from t12;
select count(*) from t13;
#select count(*) from t14;
select count(*) from t16;
if ($you_want_to_test_UDF)
{
select count(*) from t6;
......@@ -196,21 +448,48 @@ if ($you_want_to_test_UDF)
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;
connection master;
# As one stored function's parameter is UUID(), its value ends up in a
# NAME_CONST in the binlog, we must hide it for repeatability
--replace_column 2 # 5 #
--replace_regex /table_id: [0-9]+/table_id: #/ /NAME_CONST\('x',.*/NAME_CONST('x',.../
show binlog events from 102;
# Now test that mysqlbinlog works fine on a binlog generated by the
# mixed mode
# BUG#11312 "DELIMITER is not written to the binary log that causes
# syntax error" makes that mysqlbinlog will fail if we pass it the
# text of queries; this forces us to use --base64-output here.
# BUG#20929 "BINLOG command causes invalid free plus assertion
# failure" makes mysqld segfault when receiving --base64-output
# So I can't enable this piece of test
# SIGH
if ($enable_when_11312_or_20929_fixed)
{
--exec $MYSQL_BINLOG --base64-output $MYSQLTEST_VARDIR/log/master-bin.000001 > $MYSQLTEST_VARDIR/tmp/mysqlbinlog_mixed.sql
drop database mysqltest1;
--exec $MYSQL < $MYSQLTEST_VARDIR/tmp/mysqlbinlog_mixed.sql
--exec $MYSQL_DUMP --compact --order-by-primary --skip-extended-insert --no-create-info mysqltest1 > $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_master.sql
# the old mysqldump output on slave is the same as what it was on
# master before restoring on master.
--exec diff $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_master.sql $MYSQLTEST_VARDIR/tmp/rpl_switch_stm_row_mixed_slave.sql;
}
drop database mysqltest1;
sync_slave_with_master;
......@@ -426,7 +426,9 @@ Item *create_func_unhex(Item* a)
Item *create_func_uuid(void)
{
THD *thd= current_thd;
thd->lex->binlog_row_based_if_mixed= 1;
#ifdef HAVE_ROW_BASED_REPLICATION
thd->lex->binlog_row_based_if_mixed= TRUE;
#endif
return new(thd->mem_root) Item_func_uuid();
}
......
......@@ -1343,9 +1343,9 @@ bool sys_var_thd_binlog_format::is_readonly() const
return 1;
}
/*
if in a stored function, it's too late to change mode
if in a stored function/trigger, it's too late to change mode
*/
if (thd->spcont && thd->prelocked_mode)
if (thd->in_sub_stmt)
{
my_error(ER_STORED_FUNCTION_PREVENTS_SWITCH_BINLOG_FORMAT, MYF(0));
return 1;
......
......@@ -1632,6 +1632,7 @@ sp_cache_routines_and_add_tables_aux(THD *thd, LEX *lex,
sp->add_used_tables_to_table_list(thd, &lex->query_tables_last,
rt->belong_to_view);
}
sp->propagate_attributes(lex);
}
first= FALSE;
}
......@@ -1729,14 +1730,16 @@ sp_cache_routines_and_add_tables_for_triggers(THD *thd, LEX *lex,
{
for (int j= 0; j < (int)TRG_ACTION_MAX; j++)
{
if (triggers->bodies[i][j])
sp_head *trigger_body= triggers->bodies[i][j];
if (trigger_body)
{
(void)triggers->bodies[i][j]->
(void)trigger_body->
add_used_tables_to_table_list(thd, &lex->query_tables_last,
table->belong_to_view);
sp_update_stmt_used_routines(thd, lex,
&triggers->bodies[i][j]->m_sroutines,
&trigger_body->m_sroutines,
table->belong_to_view);
trigger_body->propagate_attributes(lex);
}
}
}
......
......@@ -1675,6 +1675,16 @@ sp_head::restore_lex(THD *thd)
oldlex->next_state= sublex->next_state;
oldlex->trg_table_fields.push_back(&sublex->trg_table_fields);
#ifdef HAVE_ROW_BASED_REPLICATION
/*
If this substatement needs row-based, the entire routine does too (we
cannot switch from statement-based to row-based only for this
substatement).
*/
if (sublex->binlog_row_based_if_mixed)
m_flags|= BINLOG_ROW_BASED_IF_MIXED;
#endif
/*
Add routines which are used by statement to respective set for
this routine.
......
......@@ -126,7 +126,8 @@ public:
/* Is set if a procedure with COMMIT (implicit or explicit) | ROLLBACK */
HAS_COMMIT_OR_ROLLBACK= 128,
LOG_SLOW_STATEMENTS= 256, // Used by events
LOG_GENERAL_LOG= 512 // Used by events
LOG_GENERAL_LOG= 512, // Used by events
BINLOG_ROW_BASED_IF_MIXED= 1024
};
/* TYPE_ENUM_FUNCTION, TYPE_ENUM_PROCEDURE or TYPE_ENUM_TRIGGER */
......@@ -351,6 +352,25 @@ public:
int show_routine_code(THD *thd);
#endif
/*
This method is intended for attributes of a routine which need
to propagate upwards to the LEX of the caller (when a property of a
sp_head needs to "taint" the caller).
*/
void propagate_attributes(LEX *lex)
{
#ifdef HAVE_ROW_BASED_REPLICATION
/*
If this routine needs row-based binary logging, the entire top statement
too (we cannot switch from statement-based to row-based only for this
routine, as in statement-based the top-statement may be binlogged and
the substatements not).
*/
if (m_flags & BINLOG_ROW_BASED_IF_MIXED)
lex->binlog_row_based_if_mixed= TRUE;
#endif
}
private:
......
......@@ -49,6 +49,8 @@ static bool open_new_frm(THD *thd, TABLE_SHARE *share, const char *alias,
static void close_old_data_files(THD *thd, TABLE *table, bool abort_locks,
bool send_refresh);
static bool reopen_table(TABLE *table);
static bool
has_two_write_locked_tables_with_auto_increment(TABLE_LIST *tables);
extern "C" byte *table_cache_key(const byte *record,uint *length,
......@@ -3315,6 +3317,18 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
*need_reopen= FALSE;
#ifdef HAVE_ROW_BASED_REPLICATION
/*
CREATE ... SELECT UUID() locks no tables, we have to test here.
Note that we will not do the resetting if inside a stored
function/trigger, because the binlogging of those is decided earlier (by
the caller) and can't be changed afterwards.
*/
thd->reset_current_stmt_binlog_row_based();
if (thd->lex->binlog_row_based_if_mixed)
thd->set_current_stmt_binlog_row_based_if_mixed();
#endif /*HAVE_ROW_BASED_REPLICATION*/
if (!tables)
DBUG_RETURN(0);
......@@ -3345,6 +3359,19 @@ int lock_tables(THD *thd, TABLE_LIST *tables, uint count, bool *need_reopen)
{
thd->in_lock_tables=1;
thd->options|= OPTION_TABLE_LOCK;
#ifdef HAVE_ROW_BASED_REPLICATION
/*
If we have >= 2 different tables to update with auto_inc columns,
statement-based binlogging won't work. We can solve this problem in
mixed mode by switching to row-based binlogging:
*/
if (thd->variables.binlog_format == BINLOG_FORMAT_MIXED &&
has_two_write_locked_tables_with_auto_increment(tables))
{
thd->lex->binlog_row_based_if_mixed= TRUE;
thd->set_current_stmt_binlog_row_based_if_mixed();
}
#endif
}
if (! (thd->lock= mysql_lock_tables(thd, start, (uint) (ptr - start),
......@@ -6477,3 +6504,46 @@ void mysql_wait_completed_table(ALTER_PARTITION_PARAM_TYPE *lpt, TABLE *my_table
DBUG_VOID_RETURN;
}
/*
Tells if two (or more) tables have auto_increment columns and we want to
lock those tables with a write lock.
SYNOPSIS
has_two_write_locked_tables_with_auto_increment
tables Table list
NOTES:
Call this function only when you have established the list of all tables
which you'll want to update (including stored functions, triggers, views
inside your statement).
RETURN
0 No
1 Yes
*/
static bool
has_two_write_locked_tables_with_auto_increment(TABLE_LIST *tables)
{
char *first_table_name= NULL, *first_db;
for (TABLE_LIST *table= tables; table; table= table->next_global)
{
/* we must do preliminary checks as table->table may be NULL */
if (!table->placeholder() && !table->schema_table &&
table->table->found_next_number_field &&
(table->lock_type >= TL_WRITE_ALLOW_WRITE))
{
if (first_table_name == NULL)
{
first_table_name= table->table_name;
first_db= table->db;
DBUG_ASSERT(first_db);
}
else if (strcmp(first_db, table->db) ||
strcmp(first_table_name, table->table_name))
return 1;
}
}
return 0;
}
......@@ -1418,7 +1418,17 @@ public:
inline void set_current_stmt_binlog_row_based_if_mixed()
{
#ifdef HAVE_ROW_BASED_REPLICATION
if (variables.binlog_format == BINLOG_FORMAT_MIXED)
/*
If in a stored/function trigger, the caller should already have done the
change. We test in_sub_stmt to prevent introducing bugs where people
wouldn't ensure that, and would switch to row-based mode in the middle
of executing a stored function/trigger (which is too late, see also
reset_current_stmt_binlog_row_based()); this condition will make their
tests fail and so force them to propagate the
lex->binlog_row_based_if_mixed upwards to the caller.
*/
if ((variables.binlog_format == BINLOG_FORMAT_MIXED) &&
(in_sub_stmt == 0))
current_stmt_binlog_row_based= TRUE;
#endif
}
......@@ -1437,8 +1447,26 @@ public:
inline void reset_current_stmt_binlog_row_based()
{
#ifdef HAVE_ROW_BASED_REPLICATION
/*
If there are temporary tables, don't reset back to
statement-based. Indeed it could be that:
CREATE TEMPORARY TABLE t SELECT UUID(); # row-based
# and row-based does not store updates to temp tables
# in the binlog.
INSERT INTO u SELECT * FROM t; # stmt-based
and then the INSERT will fail as data inserted into t was not logged.
So we continue with row-based until the temp table is dropped.
If we are in a stored function or trigger, we mustn't reset in the
middle of its execution (as the binary logging way of a stored function
or trigger is decided when it starts executing, depending for example on
the caller (for a stored function: if caller is SELECT or
INSERT/UPDATE/DELETE...).
*/
if ((temporary_tables == NULL) && (in_sub_stmt == 0))
{
current_stmt_binlog_row_based=
test(variables.binlog_format == BINLOG_FORMAT_ROW);
}
#else
current_stmt_binlog_row_based= FALSE;
#endif
......
......@@ -183,7 +183,6 @@ void lex_start(THD *thd, const uchar *buf, uint length)
lex->nest_level=0 ;
lex->allow_sum_func= 0;
lex->in_sum_func= NULL;
lex->binlog_row_based_if_mixed= 0;
DBUG_VOID_RETURN;
}
......@@ -1625,6 +1624,9 @@ void Query_tables_list::reset_query_tables_list(bool init)
sroutines_list.empty();
sroutines_list_own_last= sroutines_list.next;
sroutines_list_own_elements= 0;
#ifdef HAVE_ROW_BASED_REPLICATION
binlog_row_based_if_mixed= FALSE;
#endif
}
......
......@@ -793,6 +793,16 @@ public:
byte **sroutines_list_own_last;
uint sroutines_list_own_elements;
#ifdef HAVE_ROW_BASED_REPLICATION
/*
Tells if the parsing stage detected that some items require row-based
binlogging to give a reliable binlog/replication, or if we will use
stored functions or triggers which themselves need require row-based
binlogging.
*/
bool binlog_row_based_if_mixed;
#endif
/*
These constructor and destructor serve for creation/destruction
of Query_tables_list instances which are used as backup storage.
......@@ -970,11 +980,7 @@ typedef struct st_lex : public Query_tables_list
uint8 create_view_check;
bool drop_if_exists, drop_temporary, local_file, one_shot_set;
bool in_comment, ignore_space, verbose, no_write_to_binlog;
/*
binlog_row_based_if_mixed tells if the parsing stage detected that some
items require row-based binlogging to give a reliable binlog/replication.
*/
bool tx_chain, tx_release, binlog_row_based_if_mixed;
bool tx_chain, tx_release;
/*
Special JOIN::prepare mode: changing of query is prohibited.
When creating a view, we need to just check its syntax omitting
......
......@@ -2503,11 +2503,6 @@ mysql_execute_command(THD *thd)
statistic_increment(thd->status_var.com_stat[lex->sql_command],
&LOCK_status);
#ifdef HAVE_ROW_BASED_REPLICATION
if (lex->binlog_row_based_if_mixed)
thd->set_current_stmt_binlog_row_based_if_mixed();
#endif /*HAVE_ROW_BASED_REPLICATION*/
switch (lex->sql_command) {
case SQLCOM_SHOW_EVENTS:
if ((res= check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0,
......@@ -5166,9 +5161,6 @@ end:
*/
if (thd->one_shot_set && lex->sql_command != SQLCOM_SET_OPTION)
reset_one_shot_variables(thd);
#ifdef HAVE_ROW_BASED_REPLICATION
thd->reset_current_stmt_binlog_row_based();
#endif /*HAVE_ROW_BASED_REPLICATION*/
/*
The return value for ROW_COUNT() is "implementation dependent" if the
......@@ -5846,6 +5838,11 @@ void mysql_reset_thd_for_next_command(THD *thd)
thd->rand_used= 0;
thd->sent_row_count= thd->examined_row_count= 0;
}
#ifdef HAVE_ROW_BASED_REPLICATION
/* If in a routine, we reset only at end of top statement. */
thd->reset_current_stmt_binlog_row_based();
#endif /*HAVE_ROW_BASED_REPLICATION*/
DBUG_VOID_RETURN;
}
......
......@@ -997,6 +997,15 @@ bool mysql_make_view(THD *thd, File_parser *parser, TABLE_LIST *table)
table->next_global= view_tables;
}
#ifdef HAVE_ROW_BASED_REPLICATION
/*
If the view's body needs row-based binlogging (e.g. the VIEW is created
from SELECT UUID()), the top statement also needs it.
*/
if (lex->binlog_row_based_if_mixed)
old_lex->binlog_row_based_if_mixed= TRUE;
#endif
/*
If we are opening this view as part of implicit LOCK TABLES, then
this view serves as simple placeholder and we should not continue
......
......@@ -6374,7 +6374,7 @@ simple_expr:
if (udf->type == UDFTYPE_AGGREGATE)
Select->in_sum_expr--;
Lex->binlog_row_based_if_mixed= 1;
Lex->binlog_row_based_if_mixed= TRUE;
switch (udf->returns) {
case STRING_RESULT:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment