Commit 7cac0ddf authored by unknown's avatar unknown
Browse files

WL#2977 and WL#2712 global and session-level variable to set the binlog format (row/statement),

and new binlog format called "mixed" (which is statement-based except if only row-based is correct,
in this cset it means if UDF or UUID is used; more cases could be added in later 5.1 release):
SET GLOBAL|SESSION BINLOG_FORMAT=row|statement|mixed|default;
the global default is statement unless cluster is enabled (then it's row) as in 5.1-alpha.
It's not possible to use SET on this variable if a session is currently in row-based mode and has open temporary tables (because CREATE
TEMPORARY TABLE was not binlogged so temp table is not known on slave),  or if NDB is enabled (because
NDB does not support such change on-the-fly, though it will later), of if in a stored function (see below).
The added tests test the possibility or impossibility to SET, their effects, and the mixed mode,
including in prepared statements and in stored procedures and functions.
Caveats:
a) The mixed mode will not work for stored functions: in mixed mode, a stored function will
always be binlogged as one call and in a statement-based way (e.g. INSERT VALUES(myfunc()) or SELECT myfunc()).
b) for the same reason, changing the thread's binlog format inside a stored function is
refused with an error message.
c) the same problems apply to triggers; implementing b) for triggers will be done later (will ask
Dmitri).
Additionally, as the binlog format is now changeable by each user for his session, I remove the implication
which was done at startup, where row-based automatically set log-bin-trust-routine-creators to 1
(not possible anymore as a user can now switch to stmt-based and do nasty things again), and automatically
set --innodb-locks-unsafe-for-binlog to 1 (was anyway theoretically incorrect as it disabled
phantom protection).
Plus fixes for compiler warnings.


mysql-test/r/rpl_row_4_bytes.result:
  update
mysql-test/t/rpl_row_4_bytes.test:
  don't influence next tests
sql/ha_archive.cc:
  please pay attention to this structure when you change it...
sql/ha_berkeley.cc:
  please pay attention to this structure when you change it...
sql/ha_blackhole.cc:
  please pay attention to this structure when you change it...
sql/ha_federated.cc:
  please pay attention to this structure when you change it...
sql/ha_heap.cc:
  please pay attention to this structure when you change it...
sql/ha_innodb.cc:
  please pay attention to this structure when you change it...
sql/ha_myisam.cc:
  please pay attention to this structure when you change it...
sql/ha_myisammrg.cc:
  please pay attention to this structure when you change it...
sql/ha_ndbcluster_binlog.cc:
  no more global 'binlog_row_based'
sql/ha_partition.cc:
  please pay attention to this structure when you change it...
sql/handler.cc:
  please pay attention to this structure when you change it...
sql/handler.h:
  it's good to initialize statically (to get no compiler warning) even if to a null value.
sql/item_func.cc:
  UDFs require row-based if this is the "mixed" binlog format.
sql/item_strfunc.cc:
  UUID() requires row-based binlogging if this is the "mixed" binlog format
sql/log.cc:
  binlog_row_based -> thd->current_stmt_binlog_row_based
sql/log.h:
  the enum enum_binlog_format moves to log.h from mysqld.cc as we need it in several places.
sql/log_event.cc:
  binlog_row_based -> thd->current_stmt_binlog_row_based
sql/log_event.h:
  this global variable not used anymore
sql/mysql_priv.h:
  these global variables not used anymore
sql/mysqld.cc:
  simplification in the handling of --binlog-format (but with no user-visible change), thanks to
  the new global system variable.
  RBR does not anymore turn on --log-bin-trust-function-creators and --innodb-locks-unsafe-for-binlog
  as these are global options and RBR is now settable per session.
sql/partition_info.cc:
  compiler warnings
sql/set_var.cc:
  new class of thread's variable, to handle the binlog_format (like sys_var_thd_enum except
  that is_readonly() is overriden for more checks before update).
  compiler warnings (ok'd by Serg)
sql/set_var.h:
  new class for the thread's binlog_format (see set_var.cc)
sql/share/errmsg.txt:
  some messages for when one can't toggle from one binlog format to another
sql/sp_head.cc:
  binlog_row_based -> thd->current_stmt_binlog_row_based
sql/sql_base.cc:
  binlog_row_based -> thd->current_stmt_binlog_row_based
sql/sql_class.cc:
  When a THD is initialized, we set its current_stmt_binlog_row_based
sql/sql_class.h:
  new THD::variables.binlog_format (the value of the session variable set by SET
  or inherited from the global value), and THD::current_stmt_binlog_row_based which tells if the
  current statement does row-based or statement-based binlogging. Both members are needed
  as the 2nd one cannot be derived only from the first one (the statement's type plays a role too),
  and the 1st one is needed to reset the 2nd one.
sql/sql_delete.cc:
  binlog_row_based -> thd->current_stmt_binlog_row_based
sql/sql_insert.cc:
  binlog_row_based -> thd->current_stmt_binlog_row_based
sql/sql_load.cc:
  binlog_row_based -> thd->current_stmt_binlog_row_based.
sql/sql_parse.cc:
  when we are done with a statement, we reset the current_stmt_binlog_row_based to the value
  derived from THD::variables.binlog_format.
sql/sql_partition.cc:
  compiler warning
sql/sql_show.cc:
  compiler warning
sql/sql_table.cc:
  binlog_row_based -> thd->current_stmt_binlog_row_based
tests/mysql_client_test.c:
  compiler warning
mysql-test/r/ndb_binlog_basic2.result:
  new result
mysql-test/r/rpl_switch_stm_row_mixed.result:
  new result
mysql-test/t/ndb_binlog_basic2.test:
  new test to verify that if cluster is enabled, can't change binlog format on the fly.
mysql-test/t/rpl_switch_stm_row_mixed.test:
  test to see if one can switch between SBR, RBR, and "mixed" mode, and when one cannot,
  and test to see if the switching, and the mixed mode, work properly (using UUID() to test,
  as using UDFs is not possible in the testsuite for portability reasons).
parent 5e02bec9
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
set session binlog_format=row;
ERROR HY000: The NDB cluster engine does not support changing the binlog format on the fly yet
set session binlog_format=statement;
ERROR HY000: The NDB cluster engine does not support changing the binlog format on the fly yet
set global binlog_format=row;
ERROR HY000: The NDB cluster engine does not support changing the binlog format on the fly yet
set global binlog_format=statement;
ERROR HY000: The NDB cluster engine does not support changing the binlog format on the fly yet
set session binlog_format=default;
ERROR HY000: The NDB cluster engine does not support changing the binlog format on the fly yet
set global binlog_format=default;
ERROR HY000: The NDB cluster engine does not support changing the binlog format on the fly yet
+1 −1
Original line number Diff line number Diff line
@@ -24,4 +24,4 @@ a
ABE
ANG
LIL
DROP TABLE t1,t2;
DROP DATABASE mysqltest1;
+224 −0
Original line number Diff line number Diff line
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
drop database if exists mysqltest1;
create database mysqltest1;
use mysqltest1;
show global variables like "binlog_format%";
Variable_name	Value
binlog_format	ROW
show session variables like "binlog_format%";
Variable_name	Value
binlog_format	ROW
select @@global.binlog_format, @@session.binlog_format;
@@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");
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";
create temporary table tmp(a char(3));
insert into tmp values("see");
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;
drop temporary table tmp;
set binlog_format=statement;
show global variables like "binlog_format%";
Variable_name	Value
binlog_format	ROW
show session variables like "binlog_format%";
Variable_name	Value
binlog_format	STATEMENT
select @@global.binlog_format, @@session.binlog_format;
@@global.binlog_format	@@session.binlog_format
ROW	STATEMENT
set global binlog_format=statement;
show global variables like "binlog_format%";
Variable_name	Value
binlog_format	STATEMENT
show session variables like "binlog_format%";
Variable_name	Value
binlog_format	STATEMENT
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");
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";
set binlog_format=default;
select @@global.binlog_format, @@session.binlog_format;
@@global.binlog_format	@@session.binlog_format
STATEMENT	STATEMENT
set global binlog_format=default;
ERROR 42000: Variable 'binlog_format' doesn't have a default value
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");
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";
set binlog_format=mixed;
select @@global.binlog_format, @@session.binlog_format;
@@global.binlog_format	@@session.binlog_format
STATEMENT	MIXED
set global binlog_format=mixed;
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");
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";
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|
call foo();
call foo2();
select foo3();
ERROR HY000: Cannot change the binary logging format inside a stored function or trigger
select * from t1 where a="alarm";
a
show binlog events from 102;
Log_name	Pos	Event_type	Server_id	End_log_pos	Info
master-bin.000001	102	Query	1	205	drop database if exists mysqltest1
master-bin.000001	205	Query	1	300	create database mysqltest1
master-bin.000001	300	Query	1	401	use `mysqltest1`; CREATE TABLE t1 (a varchar(100))
master-bin.000001	401	Table_map	1	446	mysqltest1.t1
master-bin.000001	446	Write_rows	1	481	
master-bin.000001	481	Table_map	1	526	mysqltest1.t1
master-bin.000001	526	Write_rows	1	602	
master-bin.000001	602	Table_map	1	647	mysqltest1.t1
master-bin.000001	647	Write_rows	1	718	
master-bin.000001	718	Table_map	1	763	mysqltest1.t1
master-bin.000001	763	Write_rows	1	803	
master-bin.000001	803	Table_map	1	848	mysqltest1.t1
master-bin.000001	848	Write_rows	1	918	
master-bin.000001	918	Table_map	1	963	mysqltest1.t1
master-bin.000001	963	Write_rows	1	1003	
master-bin.000001	1003	Table_map	1	1048	mysqltest1.t1
master-bin.000001	1048	Write_rows	1	1082	
master-bin.000001	1082	Query	1	1180	use `mysqltest1`; insert into t1 values("work")
master-bin.000001	1180	User var	1	1228	@`string`=_latin1 0x656D657267656E6379 COLLATE latin1_swedish_ci
master-bin.000001	1228	Query	1	1328	use `mysqltest1`; insert into t1 select @'string'
master-bin.000001	1328	Query	1	1426	use `mysqltest1`; insert into t1 values("work")
master-bin.000001	1426	User var	1	1474	@`string`=_latin1 0x656D657267656E6379 COLLATE latin1_swedish_ci
master-bin.000001	1474	Query	1	1574	use `mysqltest1`; insert into t1 select @'string'
master-bin.000001	1574	Query	1	1671	use `mysqltest1`; insert into t1 values("for")
master-bin.000001	1671	Query	1	1773	use `mysqltest1`; insert into t1 select "yesterday"
master-bin.000001	1773	Query	1	1871	use `mysqltest1`; insert into t1 values("work")
master-bin.000001	1871	User var	1	1919	@`string`=_latin1 0x656D657267656E6379 COLLATE latin1_swedish_ci
master-bin.000001	1919	Query	1	2019	use `mysqltest1`; insert into t1 select @'string'
master-bin.000001	2019	Query	1	2117	use `mysqltest1`; insert into t1 values("work")
master-bin.000001	2117	User var	1	2165	@`string`=_latin1 0x656D657267656E6379 COLLATE latin1_swedish_ci
master-bin.000001	2165	Query	1	2265	use `mysqltest1`; insert into t1 select @'string'
master-bin.000001	2265	Query	1	2362	use `mysqltest1`; insert into t1 values("for")
master-bin.000001	2362	Query	1	2464	use `mysqltest1`; insert into t1 select "yesterday"
master-bin.000001	2464	Query	1	2562	use `mysqltest1`; insert into t1 values("work")
master-bin.000001	2562	Table_map	1	2607	mysqltest1.t1
master-bin.000001	2607	Write_rows	1	2683	
master-bin.000001	2683	Table_map	1	2728	mysqltest1.t1
master-bin.000001	2728	Write_rows	1	2799	
master-bin.000001	2799	User var	1	2847	@`string`=_latin1 0x656D657267656E6379 COLLATE latin1_swedish_ci
master-bin.000001	2847	Query	1	2947	use `mysqltest1`; insert into t1 select @'string'
master-bin.000001	2947	Table_map	1	2992	mysqltest1.t1
master-bin.000001	2992	Write_rows	1	3062	
master-bin.000001	3062	Query	1	3164	use `mysqltest1`; insert into t1 select "yesterday"
master-bin.000001	3164	Table_map	1	3209	mysqltest1.t1
master-bin.000001	3209	Write_rows	1	3280	
master-bin.000001	3280	User var	1	3328	@`string`=_latin1 0x656D657267656E6379 COLLATE latin1_swedish_ci
master-bin.000001	3328	Query	1	3428	use `mysqltest1`; insert into t1 select @'string'
master-bin.000001	3428	Table_map	1	3473	mysqltest1.t1
master-bin.000001	3473	Write_rows	1	3543	
master-bin.000001	3543	Query	1	3645	use `mysqltest1`; insert into t1 select "yesterday"
master-bin.000001	3645	Query	1	3857	use `mysqltest1`; create procedure foo()
begin
insert into t1 values("work");
insert into t1 values(concat("for",UUID()));
insert into t1 select "yesterday";
end
master-bin.000001	3857	Query	1	4214	use `mysqltest1`; 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
master-bin.000001	4214	Query	1	4442	use `mysqltest1`; create function foo3() returns bigint unsigned
begin
set session binlog_format=row; # rejected for stored funcs
insert into t1 values("alarm");
return 100;
end
master-bin.000001	4442	Query	1	4548	use `mysqltest1`; insert into t1 values("work")
master-bin.000001	4548	Table_map	1	4593	mysqltest1.t1
master-bin.000001	4593	Write_rows	1	4663	
master-bin.000001	4663	Query	1	4773	use `mysqltest1`; insert into t1 select "yesterday"
master-bin.000001	4773	Table_map	1	4818	mysqltest1.t1
master-bin.000001	4818	Write_rows	1	4894	
master-bin.000001	4894	Query	1	5000	use `mysqltest1`; insert into t1 values("work")
master-bin.000001	5000	Table_map	1	5045	mysqltest1.t1
master-bin.000001	5045	Write_rows	1	5115	
master-bin.000001	5115	Table_map	1	5160	mysqltest1.t1
master-bin.000001	5160	Write_rows	1	5200	
drop database mysqltest1;
+14 −0
Original line number Diff line number Diff line
-- source include/have_ndb.inc

--error ER_NDB_CANT_SWITCH_BINLOG_FORMAT
set session binlog_format=row;
--error ER_NDB_CANT_SWITCH_BINLOG_FORMAT
set session binlog_format=statement;
--error ER_NDB_CANT_SWITCH_BINLOG_FORMAT
set global binlog_format=row;
--error ER_NDB_CANT_SWITCH_BINLOG_FORMAT
set global binlog_format=statement;
--error ER_NDB_CANT_SWITCH_BINLOG_FORMAT
set session binlog_format=default;
--error ER_NDB_CANT_SWITCH_BINLOG_FORMAT
set global binlog_format=default;
+1 −1
Original line number Diff line number Diff line
@@ -29,5 +29,5 @@ select * from t1 order by a;
select * from t2 order by a;

connection master;
DROP TABLE t1,t2;
DROP DATABASE mysqltest1;
sync_slave_with_master;
Loading