Commit 56bed24c authored by guilhem@mysql.com's avatar guilhem@mysql.com

Fix for BUG#14769 "Function fails to replicate if fails half-way (slave stops)":

if the function, invoked in a non-binlogged caller (e.g. SELECT, DO), failed half-way on the master,
slave would stop and complain that error code between him and master mismatch. 
To solve this, when a stored function is invoked in a non-binlogged caller (e.g. SELECT, DO), we binlog the function
call as SELECT instead of as DO (see revision comment of sp_head.cc for more).
And: minor wording change in the help text.
This cset will cause conflicts in 5.1, I'll merge.
parent 4c5d18b1
...@@ -233,20 +233,25 @@ end @ # # ...@@ -233,20 +233,25 @@ end @ # #
delete from t2; delete from t2;
alter table t2 add unique (a); alter table t2 add unique (a);
drop function fn1; drop function fn1;
create function fn1() create function fn1(x int)
returns int returns int
begin begin
insert into t2 values(20),(20); insert into t2 values(x),(x);
return 10; return 10;
end| end|
select fn1(); do fn1(100);
Warnings:
Error 1062 Duplicate entry '100' for key 1
select fn1(20);
ERROR 23000: Duplicate entry '20' for key 1 ERROR 23000: Duplicate entry '20' for key 1
select * from t2; select * from t2;
a a
20 20
100
select * from t2; select * from t2;
a a
20 20
100
create trigger trg before insert on t1 for each row set new.a= 10; create trigger trg before insert on t1 for each row set new.a= 10;
ERROR 42000: Access denied; you need the SUPER privilege for this operation ERROR 42000: Access denied; you need the SUPER privilege for this operation
delete from t1; delete from t1;
...@@ -324,7 +329,7 @@ insert into t1 values (x); ...@@ -324,7 +329,7 @@ insert into t1 values (x);
return x+2; return x+2;
end end
master-bin.000001 # Query 1 # use `mysqltest1`; delete t1,t2 from t1,t2 master-bin.000001 # Query 1 # use `mysqltest1`; delete t1,t2 from t1,t2
master-bin.000001 # Query 1 # use `mysqltest1`; DO `fn1`(20) master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `fn1`(20)
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(fn1(21)) master-bin.000001 # Query 1 # use `mysqltest1`; insert into t2 values(fn1(21))
master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1 master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1
master-bin.000001 # Query 1 # use `mysqltest1`; create function fn1() master-bin.000001 # Query 1 # use `mysqltest1`; create function fn1()
...@@ -351,13 +356,14 @@ end ...@@ -351,13 +356,14 @@ end
master-bin.000001 # Query 1 # use `mysqltest1`; delete from t2 master-bin.000001 # Query 1 # use `mysqltest1`; delete from t2
master-bin.000001 # Query 1 # use `mysqltest1`; alter table t2 add unique (a) master-bin.000001 # Query 1 # use `mysqltest1`; alter table t2 add unique (a)
master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1 master-bin.000001 # Query 1 # use `mysqltest1`; drop function fn1
master-bin.000001 # Query 1 # use `mysqltest1`; create function fn1() master-bin.000001 # Query 1 # use `mysqltest1`; create function fn1(x int)
returns int returns int
begin begin
insert into t2 values(20),(20); insert into t2 values(x),(x);
return 10; return 10;
end end
master-bin.000001 # Query 1 # use `mysqltest1`; DO `fn1`() master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `fn1`(100)
master-bin.000001 # Query 1 # use `mysqltest1`; SELECT `fn1`(20)
master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1 master-bin.000001 # Query 1 # use `mysqltest1`; delete from t1
master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` trigger trg before insert on t1 for each row set new.a= 10 master-bin.000001 # Query 1 # use `mysqltest1`; CREATE DEFINER=`root`@`localhost` trigger trg before insert on t1 for each row set new.a= 10
master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (1) master-bin.000001 # Query 1 # use `mysqltest1`; insert into t1 values (1)
...@@ -415,4 +421,3 @@ col ...@@ -415,4 +421,3 @@ col
test test
DROP PROCEDURE p1; DROP PROCEDURE p1;
drop table t1; drop table t1;
reset master;
--log_bin_trust_routine_creators=0 --slave-skip-errors=1062 --log_bin_trust_routine_creators=0
...@@ -294,21 +294,19 @@ alter table t2 add unique (a); ...@@ -294,21 +294,19 @@ alter table t2 add unique (a);
drop function fn1; drop function fn1;
delimiter |; delimiter |;
create function fn1() create function fn1(x int)
returns int returns int
begin begin
insert into t2 values(20),(20); insert into t2 values(x),(x);
return 10; return 10;
end| end|
delimiter ;| delimiter ;|
# Because of BUG#14769 the following statement requires that we start do fn1(100);
# slave with --slave-skip-errors=1062. When that bug is fixed, that
# option can be removed.
--error 1062 --error 1062
select fn1(); select fn1(20);
select * from t2; select * from t2;
sync_slave_with_master; sync_slave_with_master;
...@@ -440,4 +438,4 @@ DROP PROCEDURE p1; ...@@ -440,4 +438,4 @@ DROP PROCEDURE p1;
# cleanup # cleanup
connection master; connection master;
drop table t1; drop table t1;
reset master; sync_slave_with_master;
...@@ -4923,8 +4923,8 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite, ...@@ -4923,8 +4923,8 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite,
*/ */
{"log-bin-trust-function-creators", OPT_LOG_BIN_TRUST_FUNCTION_CREATORS, {"log-bin-trust-function-creators", OPT_LOG_BIN_TRUST_FUNCTION_CREATORS,
"If equal to 0 (the default), then when --log-bin is used, creation of " "If equal to 0 (the default), then when --log-bin is used, creation of "
"a function is allowed only to users having the SUPER privilege and only " "a stored function is allowed only to users having the SUPER privilege and"
"if this function may not break binary logging.", " only if this function may not break binary logging.",
(gptr*) &trust_function_creators, (gptr*) &trust_function_creators, 0, (gptr*) &trust_function_creators, (gptr*) &trust_function_creators, 0,
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
{"log-error", OPT_ERROR_LOG_FILE, "Error log file.", {"log-error", OPT_ERROR_LOG_FILE, "Error log file.",
......
...@@ -736,13 +736,7 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b) ...@@ -736,13 +736,7 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b)
Statements that have is_update_query(stmt) == FALSE (e.g. SELECTs) are not Statements that have is_update_query(stmt) == FALSE (e.g. SELECTs) are not
written into binary log. Instead we catch function calls the statement written into binary log. Instead we catch function calls the statement
makes and write it into binary log separately (see #3). makes and write it into binary log separately (see #3).
We actually can easily write SELECT statements into the binary log in the
right order (we don't have issues with const tables being unlocked early
because SELECTs that use FUNCTIONs unlock all tables at once) We don't do
it because replication slave thread currently can't execute SELECT
statements. Fixing this is on the TODO.
2. PROCEDURE calls 2. PROCEDURE calls
CALL statements are not written into binary log. Instead CALL statements are not written into binary log. Instead
...@@ -763,7 +757,7 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b) ...@@ -763,7 +757,7 @@ int cmp_splocal_locations(Item_splocal * const *a, Item_splocal * const *b)
function execution (grep for start_union_events and stop_union_events) function execution (grep for start_union_events and stop_union_events)
If the answers are No and Yes, we write the function call into the binary If the answers are No and Yes, we write the function call into the binary
log as "DO spfunc(<param1value>, <param2value>, ...)" log as "SELECT spfunc(<param1value>, <param2value>, ...)".
4. Miscellaneous issues. 4. Miscellaneous issues.
...@@ -1310,7 +1304,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, ...@@ -1310,7 +1304,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount,
char buf[256]; char buf[256];
String bufstr(buf, sizeof(buf), &my_charset_bin); String bufstr(buf, sizeof(buf), &my_charset_bin);
bufstr.length(0); bufstr.length(0);
bufstr.append(STRING_WITH_LEN("DO ")); bufstr.append(STRING_WITH_LEN("SELECT "));
append_identifier(thd, &bufstr, m_name.str, m_name.length); append_identifier(thd, &bufstr, m_name.str, m_name.length);
bufstr.append('('); bufstr.append('(');
for (uint i=0; i < argcount; i++) for (uint i=0; i < argcount; i++)
......
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