Commit 90e25c6f authored by 's avatar

Bug #44331 Restore of database with events produces warning in replication

If an EVENT is created without the DEFINER clause set explicitly or with it set  
to CURRENT_USER, the master and slaves become inconsistent. This issue stems from 
the fact that in both cases, the DEFINER is set to the CURRENT_USER of the current 
thread. On the master, the CURRENT_USER is the mysqld's user, while on the slave,  
the CURRENT_USER is empty for the SQL Thread which is responsible for executing 
the statement.

To fix the problem, we do what follows. If the definer is not set explicitly,  
a DEFINER clause is added when writing the query into binlog; if 'CURRENT_USER' is 
used as the DEFINER, it is replaced with the value of the current user before 
writing to binlog.
parent 2d6c97e0
......@@ -29,5 +29,5 @@ t1
t2
SHOW EVENTS in mysqltest;
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation
mysqltest e @ SYSTEM ONE TIME # NULL NULL NULL NULL SLAVESIDE_DISABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci
mysqltest e root@localhost SYSTEM ONE TIME # NULL NULL NULL NULL SLAVESIDE_DISABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci
DROP DATABASE IF EXISTS mysqltest;
......@@ -43,7 +43,7 @@ master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS db_bug_13684.t
master-bin.000001 # Query # # DROP DATABASE IF EXISTS db_bug_13684
master-bin.000001 # Query # # CREATE DATABASE db_bug_13684
master-bin.000001 # Query # # use `test`; CREATE TABLE db_bug_13684.t (a int)
master-bin.000001 # Query # # use `test`; CREATE EVENT db_bug_13684.e
master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` EVENT db_bug_13684.e
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
DO
UPDATE db_bug_13684.t SET a = a + 1
......@@ -75,7 +75,7 @@ master-bin.000001 # Query # # use `test`; DROP TABLE IF EXISTS db_bug_13684.t
master-bin.000001 # Query # # DROP DATABASE IF EXISTS db_bug_13684
master-bin.000001 # Query # # CREATE DATABASE db_bug_13684
master-bin.000001 # Query # # use `test`; CREATE TABLE db_bug_13684.t (a int)
master-bin.000001 # Query # # use `test`; CREATE EVENT db_bug_13684.e
master-bin.000001 # Query # # use `test`; CREATE DEFINER=`root`@`localhost` EVENT db_bug_13684.e
ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 HOUR
DO
UPDATE db_bug_13684.t SET a = a + 1
......
......@@ -191,5 +191,47 @@ select * from t28953;
END;|
ALTER EVENT event1 RENAME TO event2;
DROP EVENT event2;
CREATE TABLE test.t1(details CHAR(30));
CREATE EVENT /*!50000 event44331_1 */
ON SCHEDULE AT CURRENT_TIMESTAMP
ON COMPLETION PRESERVE DISABLE
DO INSERT INTO test.t1 VALUES('event event44331_1 fired - no definer');
CREATE DEFINER=CURRENT_USER /*!50000 EVENT event44331_2 */
ON SCHEDULE AT CURRENT_TIMESTAMP
ON COMPLETION PRESERVE DISABLE
DO INSERT INTO test.t1 VALUES('event event44331_2 fired - DEFINER=CURRENT_USER');
CREATE DEFINER=CURRENT_USER() EVENT event44331_3
ON SCHEDULE AT CURRENT_TIMESTAMP
ON COMPLETION PRESERVE DISABLE
DO INSERT INTO test.t1 VALUES('event event44331_3 fired - DEFINER=CURRENT_USER() function');
CREATE /*!50000 DEFINER='user44331' */ EVENT event44331_4
ON SCHEDULE AT CURRENT_TIMESTAMP
ON COMPLETION PRESERVE DISABLE
DO INSERT INTO test.t1 VALUES('event event44331_4 fired - DEFINER=user1');
Warnings:
Note 1449 The user specified as a definer ('user44331'@'%') does not exist
#on master
select EVENT_SCHEMA, EVENT_NAME, DEFINER from information_schema.events
where EVENT_NAME='event44331_1' || EVENT_NAME='event44331_2' ||
EVENT_NAME='event44331_3' || EVENT_NAME='event44331_4';
EVENT_SCHEMA EVENT_NAME DEFINER
test event44331_1 root@localhost
test event44331_2 root@localhost
test event44331_3 root@localhost
test event44331_4 user44331@%
#on slave
select EVENT_SCHEMA, EVENT_NAME, DEFINER from information_schema.events
where EVENT_NAME='event44331_1' || EVENT_NAME='event44331_2' ||
EVENT_NAME='event44331_3' || EVENT_NAME='event44331_4';
EVENT_SCHEMA EVENT_NAME DEFINER
test event44331_1 root@localhost
test event44331_2 root@localhost
test event44331_3 root@localhost
test event44331_4 user44331@%
SET @@global.event_scheduler= @old_event_scheduler;
DROP TABLE t28953;
DROP TABLE t1;
DROP EVENT event44331_1;
DROP EVENT event44331_2;
DROP EVENT event44331_3;
DROP EVENT event44331_4;
......@@ -690,7 +690,7 @@ test_rpl e1 root@localhost SYSTEM RECURRING NULL 1 # # NULL ENABLED 1 latin1 lat
USE test_rpl;
SHOW EVENTS;
Db Name Definer Time zone Type Execute at Interval value Interval field Starts Ends Status Originator character_set_client collation_connection Database Collation
test_rpl e1 @ SYSTEM RECURRING NULL 1 # # NULL SLAVESIDE_DISABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci
test_rpl e1 root@localhost SYSTEM RECURRING NULL 1 # # NULL SLAVESIDE_DISABLED 1 latin1 latin1_swedish_ci latin1_swedish_ci
==========MASTER==========
SELECT COUNT(*) FROM t1;
COUNT(*)
......@@ -1078,7 +1078,7 @@ master-bin.000001 # Query 1 # use `test_rpl`; GRANT EVENT ON *.* TO 'root'@'loca
master-bin.000001 # Query 1 # BEGIN
master-bin.000001 # Query 1 # use `test_rpl`; INSERT INTO t1 VALUES(1, 'test1')
master-bin.000001 # Xid 1 # #
master-bin.000001 # Query 1 # use `test_rpl`; CREATE EVENT e1 ON SCHEDULE EVERY '1' SECOND COMMENT 'e_second_comment' DO DELETE FROM t1
master-bin.000001 # Query 1 # use `test_rpl`; CREATE DEFINER=`root`@`localhost` EVENT e1 ON SCHEDULE EVERY '1' SECOND COMMENT 'e_second_comment' DO DELETE FROM t1
master-bin.000001 # Query 1 # use `test_rpl`; ALTER EVENT e1 RENAME TO e2
master-bin.000001 # Query 1 # use `test_rpl`; DROP EVENT e2
master-bin.000001 # Query 1 # BEGIN
......
......@@ -46,12 +46,52 @@ connection master;
DROP EVENT event2;
sync_slave_with_master;
#
# BUG#44331
# This test verifies if the definer is consistent between master and slave,
# when the event is created without the DEFINER clause set explicitly or the
# DEFINER is set to CURRENT_USER
#
CREATE TABLE test.t1(details CHAR(30));
CREATE EVENT /*!50000 event44331_1 */
ON SCHEDULE AT CURRENT_TIMESTAMP
ON COMPLETION PRESERVE DISABLE
DO INSERT INTO test.t1 VALUES('event event44331_1 fired - no definer');
CREATE DEFINER=CURRENT_USER /*!50000 EVENT event44331_2 */
ON SCHEDULE AT CURRENT_TIMESTAMP
ON COMPLETION PRESERVE DISABLE
DO INSERT INTO test.t1 VALUES('event event44331_2 fired - DEFINER=CURRENT_USER');
CREATE DEFINER=CURRENT_USER() EVENT event44331_3
ON SCHEDULE AT CURRENT_TIMESTAMP
ON COMPLETION PRESERVE DISABLE
DO INSERT INTO test.t1 VALUES('event event44331_3 fired - DEFINER=CURRENT_USER() function');
CREATE /*!50000 DEFINER='user44331' */ EVENT event44331_4
ON SCHEDULE AT CURRENT_TIMESTAMP
ON COMPLETION PRESERVE DISABLE
DO INSERT INTO test.t1 VALUES('event event44331_4 fired - DEFINER=user1');
--echo #on master
select EVENT_SCHEMA, EVENT_NAME, DEFINER from information_schema.events
where EVENT_NAME='event44331_1' || EVENT_NAME='event44331_2' ||
EVENT_NAME='event44331_3' || EVENT_NAME='event44331_4';
# Doing cleanup of the table referred to in the event to guarantee
# that there is no bad timing cauing it to try to access the table.
sync_slave_with_master;
connection slave;
--echo #on slave
select EVENT_SCHEMA, EVENT_NAME, DEFINER from information_schema.events
where EVENT_NAME='event44331_1' || EVENT_NAME='event44331_2' ||
EVENT_NAME='event44331_3' || EVENT_NAME='event44331_4';
connection master;
SET @@global.event_scheduler= @old_event_scheduler;
DROP TABLE t28953;
DROP TABLE t1;
DROP EVENT event44331_1;
DROP EVENT event44331_2;
DROP EVENT event44331_3;
DROP EVENT event44331_4;
sync_slave_with_master;
......@@ -341,6 +341,33 @@ Events::reconstruct_interval_expression(String *buf, interval_type interval,
}
/**
Create a new query string for removing executable comments
for avoiding leak and keeping consistency of the execution
on master and slave.
@param[in] thd Thread handler
@param[in] buf Query string
@return
0 ok
1 error
*/
static int
create_query_string(THD *thd, String *buf)
{
/* Append the "CREATE" part of the query */
if (buf->append(STRING_WITH_LEN("CREATE ")))
return 1;
/* Append definer */
append_definer(thd, buf, &(thd->lex->definer->user), &(thd->lex->definer->host));
/* Append the left part of thd->query after "DEFINER" part */
if (buf->append(thd->lex->stmt_definition_begin))
return 1;
return 0;
}
/**
Create a new event.
......@@ -439,7 +466,16 @@ Events::create_event(THD *thd, Event_parse_data *parse_data,
{
/* Binlog the create event. */
DBUG_ASSERT(thd->query && thd->query_length);
write_bin_log(thd, TRUE, thd->query, thd->query_length);
String log_query;
if (create_query_string(thd, &log_query))
{
sql_print_error("Event Error: An error occurred while creating query string, "
"before writing it into binary log.");
DBUG_RETURN(TRUE);
}
/* If the definer is not set or set to CURRENT_USER, the value of CURRENT_USER
will be written into the binary log as the definer for the SQL thread. */
write_bin_log(thd, TRUE, log_query.c_ptr(), log_query.length());
}
}
pthread_mutex_unlock(&LOCK_event_metadata);
......
......@@ -1809,15 +1809,16 @@ server_option:
;
event_tail:
EVENT_SYM opt_if_not_exists sp_name
remember_name EVENT_SYM opt_if_not_exists sp_name
{
THD *thd= YYTHD;
LEX *lex=Lex;
lex->create_info.options= $2;
lex->stmt_definition_begin= $1;
lex->create_info.options= $3;
if (!(lex->event_parse_data= Event_parse_data::new_instance(thd)))
MYSQL_YYABORT;
lex->event_parse_data->identifier= $3;
lex->event_parse_data->identifier= $4;
lex->event_parse_data->on_completion=
Event_parse_data::ON_COMPLETION_DROP;
......
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