List:Commits« Previous MessageNext Message »
From:Tatiana A. Nurnberg Date:August 18 2008 11:06am
Subject:bzr commit into mysql-5.1 branch (azundris:2654) Bug#35981
View as plain text  
#At file:///misc/mysql/forest/35981_/51-35981/

 2654 Tatiana A. Nurnberg	2008-08-18
      Bug#35981: ALTER EVENT causes the server to change the PRESERVE option.
      
      If [NOT] PRESERVE was not given, parser always defaulted to NOT
      PRESERVE, making it impossible for the "not given = no change"
      rule to work in ALTER EVENT. Leaving out the PRESERVE-clause
      defaults to NOT PRESERVE on CREATE now, and to "no change" in
      ALTER.
modified:
  mysql-test/r/events_2.result
  mysql-test/t/events_2.test
  sql/event_db_repository.cc
  sql/event_parse_data.cc
  sql/event_parse_data.h
  sql/sql_yacc.yy

per-file messages:
  mysql-test/r/events_2.result
    show that giving no PRESERVE-clause to ALTER EVENT
    results in no change. show that giving no PRESERVE-clause
    to CREATE EVENT defaults to NOT PRESERVE as per the docs.
    Show specifically that this is also handled correctly when
    trying to ALTER EVENTs into the past.
  mysql-test/t/events_2.test
    show that giving no PRESERVE-clause to ALTER EVENT
    results in no change. show that giving no PRESERVE-clause
    to CREATE EVENT defaults to NOT PRESERVE as per the docs.
    Show specifically that this is also handled correctly when
    trying to ALTER EVENTs into the past.
  sql/event_db_repository.cc
    If ALTER EVENT was given no PRESERVE-clause (meaning "no change"),
    we don't know the previous PRESERVE-setting by the time we check
    the parse-data. If ALTER EVENT was given dates that are in the past,
    we don't know how to react, lacking the PRESERVE-setting. Heal this
    by running the check later when we have actually read the previous
    EVENT-data.
  sql/event_parse_data.cc
    Change default for ON COMPLETION to indicate, "not specified."
    Also defer throwing errors when ALTER EVENT is given dates in
    the past but not PRESERVE-clause until we know the previous
    PRESERVE-value.
  sql/event_parse_data.h
    Add third state for ON COMPLETION [NOT] PRESERVE (preserve,
    don't, not specified).
    
    Make check_dates() public so we can defer this check until
    deeper in the callstack where we have all the required data.
  sql/sql_yacc.yy
    If CREATE EVENT is not given ON COMPLETION [NOT] PRESERVE,
    we default to NOT, as per the docs.
=== modified file 'mysql-test/r/events_2.result'
--- a/mysql-test/r/events_2.result	2008-05-13 12:06:32 +0000
+++ b/mysql-test/r/events_2.result	2008-08-18 11:05:51 +0000
@@ -328,4 +328,81 @@ create event
 оченая_строка_66
 on schedule every 2 year do select 1;
 ERROR 42000: Identifier name 'о_очень_очень_очень_очень_очень_длинна' is too long
+create event event_35981 on schedule every 6 month on completion preserve
+disable
+do
+select 1;
+The following SELECTs should all give 1
+select  count(*) from information_schema.events
+where   event_schema = database() and event_name = 'event_35981' and
+on_completion = 'PRESERVE';
+count(*)
+1
+alter   event event_35981 enable;
+select  count(*) from information_schema.events
+where   event_schema = database() and event_name = 'event_35981' and
+on_completion = 'PRESERVE';
+count(*)
+1
+alter   event event_35981 on completion not preserve;
+select  count(*) from information_schema.events
+where   event_schema = database() and event_name = 'event_35981' and
+on_completion = 'NOT PRESERVE';
+count(*)
+1
+alter   event event_35981 disable;
+select  count(*) from information_schema.events
+where   event_schema = database() and event_name = 'event_35981' and
+on_completion = 'NOT PRESERVE';
+count(*)
+1
+alter   event event_35981 on completion preserve;
+select  count(*) from information_schema.events
+where   event_schema = database() and event_name = 'event_35981' and
+on_completion = 'PRESERVE';
+count(*)
+1
+drop event event_35981;
+create event event_35981 on schedule every 6 month disable
+do
+select 1;
+select  count(*) from information_schema.events
+where   event_schema = database() and event_name = 'event_35981' and
+on_completion = 'NOT PRESERVE';
+count(*)
+1
+drop event event_35981;
+create event event_35981 on schedule every 1 hour starts current_timestamp
+on completion not preserve
+do
+select 1;
+alter event event_35981 on schedule every 1 hour starts '1999-01-01 00:00:00'
+  ends '1999-01-02 00:00:00';
+ERROR HY000: Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation.
+drop event event_35981;
+create event event_35981 on schedule every 1 hour starts current_timestamp
+on completion not preserve
+do
+select 1;
+alter event event_35981 on schedule every 1 hour starts '1999-01-01 00:00:00'
+  ends '1999-01-02 00:00:00' on completion preserve;
+Warnings:
+Note	1544	Event execution time is in the past. Event has been disabled
+drop event event_35981;
+create event event_35981 on schedule every 1 hour starts current_timestamp
+on completion preserve
+do
+select 1;
+alter event event_35981 on schedule every 1 hour starts '1999-01-01 00:00:00'
+  ends '1999-01-02 00:00:00';
+Warnings:
+Note	1544	Event execution time is in the past. Event has been disabled
+alter event event_35981 on schedule every 1 hour starts '1999-01-01 00:00:00'
+  ends '1999-01-02 00:00:00' on completion not preserve;
+ERROR HY000: Event execution time is in the past and ON COMPLETION NOT PRESERVE is set. The event was dropped immediately after creation.
+alter event event_35981 on schedule every 1 hour starts '1999-01-01 00:00:00'
+  ends '1999-01-02 00:00:00' on completion preserve;
+Warnings:
+Note	1544	Event execution time is in the past. Event has been disabled
+drop event event_35981;
 drop database events_test;

=== modified file 'mysql-test/t/events_2.test'
--- a/mysql-test/t/events_2.test	2008-05-13 12:06:32 +0000
+++ b/mysql-test/t/events_2.test	2008-08-18 11:05:51 +0000
@@ -411,6 +411,108 @@ create event
 очень_очень_очень_очень_очень_очень_очень_очеа_66
 on schedule every 2 year do select 1;
 
+#
+# Bug#35981: ALTER EVENT causes the server to change the PRESERVE option.
+#
+
+create event event_35981 on schedule every 6 month on completion preserve
+disable
+do
+  select 1;
+
+echo The following SELECTs should all give 1;
+
+# show current ON_COMPLETION
+select  count(*) from information_schema.events
+where   event_schema = database() and event_name = 'event_35981' and
+        on_completion = 'PRESERVE';
+
+# show ON_COMPLETION remains "PRESERVE" when not given in ALTER EVENT
+alter   event event_35981 enable;
+select  count(*) from information_schema.events
+where   event_schema = database() and event_name = 'event_35981' and
+        on_completion = 'PRESERVE';
+
+# show we can change ON_COMPLETION
+alter   event event_35981 on completion not preserve;
+select  count(*) from information_schema.events
+where   event_schema = database() and event_name = 'event_35981' and
+        on_completion = 'NOT PRESERVE';
+
+# show ON_COMPLETION remains "NOT PRESERVE" when not given in ALTER EVENT
+alter   event event_35981 disable;
+select  count(*) from information_schema.events
+where   event_schema = database() and event_name = 'event_35981' and
+        on_completion = 'NOT PRESERVE';
+
+# show we can change ON_COMPLETION
+alter   event event_35981 on completion preserve;
+select  count(*) from information_schema.events
+where   event_schema = database() and event_name = 'event_35981' and
+        on_completion = 'PRESERVE';
+
+
+drop event event_35981;
+
+create event event_35981 on schedule every 6 month disable
+do
+  select 1;
+
+# show that the defaults for CREATE EVENT are still correct (NOT PRESERVE)
+select  count(*) from information_schema.events
+where   event_schema = database() and event_name = 'event_35981' and
+        on_completion = 'NOT PRESERVE';
+
+drop event event_35981;
+
+
+# show that backdating doesn't break
+
+create event event_35981 on schedule every 1 hour starts current_timestamp
+  on completion not preserve
+do
+  select 1;
+
+# should fail thanks to above's NOT PRESERVE
+--error ER_EVENT_CANNOT_ALTER_IN_THE_PAST
+alter event event_35981 on schedule every 1 hour starts '1999-01-01 00:00:00'
+  ends '1999-01-02 00:00:00';
+
+drop event event_35981;
+
+create event event_35981 on schedule every 1 hour starts current_timestamp
+  on completion not preserve
+do
+  select 1;
+
+# succeed with warning
+alter event event_35981 on schedule every 1 hour starts '1999-01-01 00:00:00'
+  ends '1999-01-02 00:00:00' on completion preserve;
+
+drop event event_35981;
+
+
+
+create event event_35981 on schedule every 1 hour starts current_timestamp
+  on completion preserve
+do
+  select 1;
+
+# this should succeed thanks to above PRESERVE! give a warning though.
+alter event event_35981 on schedule every 1 hour starts '1999-01-01 00:00:00'
+  ends '1999-01-02 00:00:00';
+
+# this should fail, as the event would have passed already
+--error ER_EVENT_CANNOT_ALTER_IN_THE_PAST
+alter event event_35981 on schedule every 1 hour starts '1999-01-01 00:00:00'
+  ends '1999-01-02 00:00:00' on completion not preserve;
+
+# should succeed giving a warning
+alter event event_35981 on schedule every 1 hour starts '1999-01-01 00:00:00'
+  ends '1999-01-02 00:00:00' on completion preserve;
+
+drop event event_35981;
+
 # 
 # End of tests
 #

=== modified file 'sql/event_db_repository.cc'
--- a/sql/event_db_repository.cc	2008-02-07 10:47:39 +0000
+++ b/sql/event_db_repository.cc	2008-08-18 11:05:51 +0000
@@ -185,6 +185,8 @@ mysql_event_fill_row(THD *thd,
   DBUG_PRINT("info", ("dbname=[%s]", et->dbname.str));
   DBUG_PRINT("info", ("name  =[%s]", et->name.str));
 
+  DBUG_ASSERT(et->on_completion != Event_parse_data::ON_COMPLETION_DEFAULT);
+
   if (table->s->fields < ET_FIELD_COUNT)
   {
     /*
@@ -745,6 +747,18 @@ Event_db_repository::update_event(THD *t
 
   store_record(table,record[1]);
 
+  /*
+    We check whether ALTER EVENT was given dates that are in the past.
+    However to know how to react, we need the ON COMPLETION type. The
+    check is deferred to this point because by now we have the previous
+    setting (from the event-table) to fall back on if nothing was specified
+    in the ALTER EVENT-statement.
+  */
+
+  if (parse_data->check_dates(thd,
+                              table->field[ET_FIELD_ON_COMPLETION]->val_int()))
+    goto end;
+
   /* Don't update create on row update. */
   table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
 

=== modified file 'sql/event_parse_data.cc'
--- a/sql/event_parse_data.cc	2008-05-09 07:43:02 +0000
+++ b/sql/event_parse_data.cc	2008-08-18 11:05:51 +0000
@@ -45,7 +45,7 @@ Event_parse_data::new_instance(THD *thd)
 */
 
 Event_parse_data::Event_parse_data()
-  :on_completion(Event_parse_data::ON_COMPLETION_DROP),
+  :on_completion(Event_parse_data::ON_COMPLETION_DEFAULT),
   status(Event_parse_data::ENABLED),
   do_not_create(FALSE),
   body_changed(FALSE),
@@ -114,6 +114,12 @@ Event_parse_data::check_if_in_the_past(T
   if (ltime_utc >= (my_time_t) thd->query_start())
     return;
 
+  /*
+    We'll come back later when we have the real on_completion value
+  */
+  if (on_completion == Event_parse_data::ON_COMPLETION_DEFAULT)
+    return;
+
   if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
   {
     switch (thd->lex->sql_command) {
@@ -142,6 +148,42 @@ Event_parse_data::check_if_in_the_past(T
 
 
 /*
+  Check time/dates in ALTER EVENT
+
+  We check whether ALTER EVENT was given dates that are in the past.
+  However to know how to react, we need the ON COMPLETION type. Hence,
+  the check is deferred until we have the previous ON COMPLETION type
+  from the event-db to fall back on if nothing was specified in the
+  ALTER EVENT-statement.
+
+  SYNOPSIS
+    Event_parse_data::check_dates()
+      thd            Thread
+      on_completion  ON COMPLETION value currently in event-db.
+                     Will be overridden by value in ALTER EVENT if given.
+
+  RETURN VALUE
+    TRUE            an error occurred, do not ALTER
+    FALSE           OK
+*/
+
+bool
+Event_parse_data::check_dates(THD *thd, int previous_on_completion)
+{
+  if (on_completion == Event_parse_data::ON_COMPLETION_DEFAULT)
+  {
+    on_completion= previous_on_completion;
+    if (!ends_null)
+      check_if_in_the_past(thd, ends);
+    if (!execute_at_null)
+      check_if_in_the_past(thd, execute_at);
+  }
+  return do_not_create;
+}
+
+
+
+/*
   Sets time for execution for one-time event.
 
   SYNOPSIS

=== modified file 'sql/event_parse_data.h'
--- a/sql/event_parse_data.h	2008-05-09 07:43:02 +0000
+++ b/sql/event_parse_data.h	2008-08-18 11:05:51 +0000
@@ -38,7 +38,12 @@ public:
 
   enum enum_on_completion
   {
-    ON_COMPLETION_DROP = 1,
+    /*
+      On CREATE EVENT, DROP is the DEFAULT as per the docs.
+      On ALTER  EVENT, "no change" is the DEFAULT.
+    */
+    ON_COMPLETION_DEFAULT = 0,
+    ON_COMPLETION_DROP,
     ON_COMPLETION_PRESERVE
   };
 
@@ -80,6 +85,9 @@ public:
   bool
   check_parse_data(THD *thd);
 
+  bool
+  check_dates(THD *thd, int previous_on_completion);
+
 private:
 
   void

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2008-05-20 07:38:17 +0000
+++ b/sql/sql_yacc.yy	2008-08-18 11:05:51 +0000
@@ -1786,6 +1786,8 @@ event_tail:
             if (!(lex->event_parse_data= Event_parse_data::new_instance(thd)))
               MYSQL_YYABORT;
             lex->event_parse_data->identifier= $3;
+            lex->event_parse_data->on_completion=
+                                  Event_parse_data::ON_COMPLETION_DROP;
 
             /*
               We have to turn of CLIENT_MULTI_QUERIES while parsing a

Thread
bzr commit into mysql-5.1 branch (azundris:2654) Bug#35981Tatiana A. Nurnberg18 Aug