List:Commits« Previous MessageNext Message »
From:Dao-Gang.Qu Date:July 20 2009 1:26pm
Subject:bzr commit into mysql-5.1-bugteam branch (Dao-Gang.Qu:2994) Bug#44331
View as plain text  
#At file:///home/daogangq/mysql/bzrwork/bug44331/5.1-bugteam/ based on revid:joro@stripped

 2994 Dao-Gang.Qu@stripped	2009-07-20
      Bug #44331  Restore of database with events produces warning in replication
      
      The real problem is that if the EVENT is created without DEFINER clause set explicitly
      or the definer is set to CURRENT_USER, the definer is not consistent between master 
      and slave. Because the DEFINER is set to CURRENT_USER of the current thread. 
      The CURRENT_USER is mysqld startup user on master, but the CURRENT_USER is empty 
      on slave for slave SQL thread.
      
      For fixing the problem, the the value of CURRENT_USER will be written into the binary log as 
      default definer for slave SQL thread on master if the EVENT is created without DEFINER clause 
      set explicitly or the definer is set to CURRENT_USER.
     @ mysql-test/suite/rpl/r/rpl_events.result
        Test result of Bug#44331
     @ mysql-test/suite/rpl/t/rpl_events.test
        This test verifies if the definer is consistent between master and slave
        when the event is created without DEFINER clause set explicitly or the
        DEFINER is set to CURRENT_USER
     @ sql/events.cc
        The "create_query_string" function is added for creating a new query string 
        and insert the DEFINER clause to it.
        Added a new parameter "definer_set_mode" to 'Events::create_event' function for
        indicating the mode of the definer is set.
        The value of CURRENT_USER will be written into the binary log 
        as default definer for slave SQL thread.
     @ sql/events.h
        Added a new parameter "definer_exist" with default actual parameter to 
        'Events::create_event(...)' function declaration.

    modified:
      mysql-test/suite/rpl/r/rpl_events.result
      mysql-test/suite/rpl/t/rpl_events.test
      sql/events.cc
      sql/events.h
      sql/sql_parse.cc
=== modified file 'mysql-test/suite/rpl/r/rpl_events.result'
--- a/mysql-test/suite/rpl/r/rpl_events.result	2009-01-30 13:44:49 +0000
+++ b/mysql-test/suite/rpl/r/rpl_events.result	2009-07-20 13:26:42 +0000
@@ -191,5 +191,25 @@ select * from t28953;
 END;|
 ALTER EVENT event1 RENAME TO event2;
 DROP EVENT event2;
+CREATE TABLE test.t1(details CHAR(30));
+CREATE EVENT 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 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');
+select EVENT_SCHEMA, EVENT_NAME, DEFINER from information_schema.events
+where EVENT_NAME='event44331_1' || EVENT_NAME='event44331_2';
+EVENT_SCHEMA	EVENT_NAME	DEFINER
+test	event44331_1	root@localhost
+test	event44331_2	root@localhost
+select EVENT_SCHEMA, EVENT_NAME, DEFINER from information_schema.events
+where EVENT_NAME='event44331_1' || EVENT_NAME='event44331_2';
+EVENT_SCHEMA	EVENT_NAME	DEFINER
+test	event44331_1	root@localhost
+test	event44331_2	root@localhost
 SET @@global.event_scheduler= @old_event_scheduler;
 DROP TABLE t28953;
+DROP TABLE t1;
+DROP EVENT event44331_1;
+DROP EVENT event44331_2;

=== modified file 'mysql-test/suite/rpl/t/rpl_events.test'
--- a/mysql-test/suite/rpl/t/rpl_events.test	2009-01-30 13:44:49 +0000
+++ b/mysql-test/suite/rpl/t/rpl_events.test	2009-07-20 13:26:42 +0000
@@ -46,7 +46,29 @@ connection master;
 
 DROP EVENT event2;
 
+#
+# BUG#44331
+# This test verifies if the definer is consistent between master and slave,
+# when the event is created without DEFINER clause set explicitly or the 
+# DEFINER is set to CURRENT_USER
+#
+CREATE TABLE test.t1(details CHAR(30));
+
+CREATE EVENT 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 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');
+
+select EVENT_SCHEMA, EVENT_NAME, DEFINER from information_schema.events
+  where EVENT_NAME='event44331_1' || EVENT_NAME='event44331_2';
+
 sync_slave_with_master;
+connection slave;
+select EVENT_SCHEMA, EVENT_NAME, DEFINER from information_schema.events
+  where EVENT_NAME='event44331_1' || EVENT_NAME='event44331_2';
 
 # 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.
@@ -54,4 +76,7 @@ sync_slave_with_master;
 connection master;
 SET @@global.event_scheduler= @old_event_scheduler;
 DROP TABLE t28953;
+DROP TABLE t1;
+DROP EVENT event44331_1;
+DROP EVENT event44331_2;
 sync_slave_with_master;

=== modified file 'sql/events.cc'
--- a/sql/events.cc	2009-04-09 06:22:06 +0000
+++ b/sql/events.cc	2009-07-20 13:26:42 +0000
@@ -342,12 +342,57 @@ common_1_lev_code:
 
 
 /**
+  Create a new query string and insert the DEFINER clause to it.
+  
+  @param[in] thd                 Thread handler
+  @param[in] buf                 Query string
+  @param[in] definer_set_mode    The mode of the definer is set
+
+  @return
+             0           ok
+             1           error
+*/
+static int
+create_query_string(THD *thd, String *buf, int definer_set_mode)
+{
+  char *indexofeventkw= NULL;
+  char *indexofunderline= NULL;
+
+  if (definer_set_mode == 1)
+    /* No definer */
+    indexofeventkw= strstr(thd->query, " ");
+  else if (definer_set_mode == 2 && 
+           (indexofunderline= strstr(thd->query, "_")))
+    /* The definer is set to CURRENT_USER */
+    indexofeventkw= strstr(indexofunderline, " ");
+  
+  if (!indexofeventkw)
+    return 1;
+  /* Append the "CREATE" part of thd->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 from event keyword */
+  if (buf->append(indexofeventkw))
+    return 1;
+
+  return 0;
+}
+
+
+/**
   Create a new event.
 
   @param[in,out]  thd            THD
   @param[in]      parse_data     Event's data from parsing stage
   @param[in]      if_not_exists  Whether IF NOT EXISTS was
                                  specified
+  @param[in]      definer_set_mode  The mode of the definer is set
+                                 0  the definer is set explicitly
+                                 1  the definer is not set
+                                 2  the definer is set to CURRENT_USER
+
   In case there is an event with the same name (db) and
   IF NOT EXISTS is specified, an warning is put into the stack.
   @sa Events::drop_event for the notes about locking, pre-locking
@@ -359,7 +404,7 @@ common_1_lev_code:
 
 bool
 Events::create_event(THD *thd, Event_parse_data *parse_data,
-                     bool if_not_exists)
+                     bool if_not_exists, int definer_set_mode)
 {
   int ret;
   DBUG_ENTER("Events::create_event");
@@ -439,7 +484,13 @@ Events::create_event(THD *thd, Event_par
     {
       /* 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 (definer_set_mode && !create_query_string(thd, &log_query, definer_set_mode))
+        /* If the definer is not set or set to CURRENT_USER, the value of CURRENT_USER 
+           will be written into the binary log as definer for slave SQL thread. */
+        write_bin_log(thd, TRUE, log_query.c_ptr(), log_query.length());
+      else
+        write_bin_log(thd, TRUE, thd->query, thd->query_length);
     }
   }
   pthread_mutex_unlock(&LOCK_event_metadata);

=== modified file 'sql/events.h'
--- a/sql/events.h	2007-08-15 15:08:44 +0000
+++ b/sql/events.h	2009-07-20 13:26:42 +0000
@@ -107,7 +107,7 @@ public:
   switch_event_scheduler_state(enum enum_opt_event_scheduler new_state);
 
   static bool
-  create_event(THD *thd, Event_parse_data *parse_data, bool if_exists);
+  create_event(THD *thd, Event_parse_data *parse_data, bool if_exists, int definer_set_mode);
 
   static bool
   update_event(THD *thd, Event_parse_data *parse_data,

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2009-07-01 12:32:04 +0000
+++ b/sql/sql_parse.cc	2009-07-20 13:26:42 +0000
@@ -3707,6 +3707,17 @@ end_with_restore_list:
                "function calls as part of this statement");
       break;
     }
+ 
+    /* The definer_set_mode is assigned an initial value 0 
+       to indicate that the definer is set explicitly */
+    int definer_set_mode= 0;
+    if (!lex->definer)
+      /* The definer is not set */
+      definer_set_mode= 1;
+    else if ((lex->definer->user.str == thd->security_ctx->priv_user) &&
+             (lex->definer->host.str == thd->security_ctx->priv_host))
+      /* The definer is set to CURRENT_USER */
+      definer_set_mode= 2;
 
     res= sp_process_definer(thd);
     if (res)
@@ -3717,7 +3728,7 @@ end_with_restore_list:
     {
       bool if_not_exists= (lex->create_info.options &
                            HA_LEX_CREATE_IF_NOT_EXISTS);
-      res= Events::create_event(thd, lex->event_parse_data, if_not_exists);
+      res= Events::create_event(thd, lex->event_parse_data, if_not_exists, definer_set_mode);
       break;
     }
     case SQLCOM_ALTER_EVENT:


Attachment: [text/bzr-bundle] bzr/dao-gang.qu@sun.com-20090720132642-k4g5iwf83p61gxbv.bundle
Thread
bzr commit into mysql-5.1-bugteam branch (Dao-Gang.Qu:2994) Bug#44331Dao-Gang.Qu20 Jul
  • Re: bzr commit into mysql-5.1-bugteam branch (Dao-Gang.Qu:2994)Bug#44331Alfranio Correia23 Jul