From 8470ae9cb1327ee5089b98a148e26bb207662fd7 Mon Sep 17 00:00:00 2001 From: unknown Date: Sat, 18 Feb 2006 17:26:30 +0100 Subject: [PATCH] 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. mysql-test/r/rpl_sp.result: result update mysql-test/t/rpl_sp-slave.opt: bug just fixed so option not needed mysql-test/t/rpl_sp.test: test for more half-failed functions with DO and SELECT, to test the bug of this changeset. cleanup at the end. sql/mysqld.cc: function -> stored function (change suggested by Paul) sql/sp_head.cc: When a function updates data and is called from a non-binlogged statement (SELECT, DO), we binlog it as SELECT myfunc(), and not DO myfunc() like before. --- mysql-test/r/rpl_sp.result | 21 +++++++++++++-------- mysql-test/t/rpl_sp-slave.opt | 2 +- mysql-test/t/rpl_sp.test | 12 +++++------- sql/mysqld.cc | 4 ++-- sql/sp_head.cc | 12 +++--------- 5 files changed, 24 insertions(+), 27 deletions(-) diff --git a/mysql-test/r/rpl_sp.result b/mysql-test/r/rpl_sp.result index 7180b677b8e..a42c33ce333 100644 --- a/mysql-test/r/rpl_sp.result +++ b/mysql-test/r/rpl_sp.result @@ -233,20 +233,25 @@ end @ # # delete from t2; alter table t2 add unique (a); drop function fn1; -create function fn1() +create function fn1(x int) returns int begin -insert into t2 values(20),(20); +insert into t2 values(x),(x); return 10; 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 select * from t2; a 20 +100 select * from t2; a 20 +100 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 delete from t1; @@ -324,7 +329,7 @@ insert into t1 values (x); return x+2; end 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`; drop function fn1 master-bin.000001 # Query 1 # use `mysqltest1`; create function fn1() @@ -351,13 +356,14 @@ end 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`; 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 begin -insert into t2 values(20),(20); +insert into t2 values(x),(x); return 10; 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`; 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) @@ -415,4 +421,3 @@ col test DROP PROCEDURE p1; drop table t1; -reset master; diff --git a/mysql-test/t/rpl_sp-slave.opt b/mysql-test/t/rpl_sp-slave.opt index 611ee1f33be..709a224fd92 100644 --- a/mysql-test/t/rpl_sp-slave.opt +++ b/mysql-test/t/rpl_sp-slave.opt @@ -1 +1 @@ ---log_bin_trust_routine_creators=0 --slave-skip-errors=1062 +--log_bin_trust_routine_creators=0 diff --git a/mysql-test/t/rpl_sp.test b/mysql-test/t/rpl_sp.test index c0eaf6f817f..8be17be3822 100644 --- a/mysql-test/t/rpl_sp.test +++ b/mysql-test/t/rpl_sp.test @@ -294,21 +294,19 @@ alter table t2 add unique (a); drop function fn1; delimiter |; -create function fn1() +create function fn1(x int) returns int begin - insert into t2 values(20),(20); + insert into t2 values(x),(x); return 10; end| delimiter ;| -# Because of BUG#14769 the following statement requires that we start -# slave with --slave-skip-errors=1062. When that bug is fixed, that -# option can be removed. +do fn1(100); --error 1062 -select fn1(); +select fn1(20); select * from t2; sync_slave_with_master; @@ -440,4 +438,4 @@ DROP PROCEDURE p1; # cleanup connection master; drop table t1; -reset master; +sync_slave_with_master; diff --git a/sql/mysqld.cc b/sql/mysqld.cc index c19fdcfde82..4c32d7f9de5 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -4923,8 +4923,8 @@ Disable with --skip-innodb-doublewrite.", (gptr*) &innobase_use_doublewrite, */ {"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 " - "a function is allowed only to users having the SUPER privilege and only " - "if this function may not break binary logging.", + "a stored function is allowed only to users having the SUPER privilege and" + " only if this function may not break binary logging.", (gptr*) &trust_function_creators, (gptr*) &trust_function_creators, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"log-error", OPT_ERROR_LOG_FILE, "Error log file.", diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 27dc0103335..aff773a32bc 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -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 written into binary log. Instead we catch function calls the statement 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 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) 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 - log as "DO spfunc(, , ...)" + log as "SELECT spfunc(, , ...)". 4. Miscellaneous issues. @@ -1310,7 +1304,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, char buf[256]; String bufstr(buf, sizeof(buf), &my_charset_bin); 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); bufstr.append('('); for (uint i=0; i < argcount; i++)