Commit 4b317a56 authored by Tatiana A. Nurnberg's avatar Tatiana A. Nurnberg
Browse files

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.
parent 0e62334a
Loading
Loading
Loading
Loading
+77 −0
Original line number Diff line number Diff line
@@ -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;
+102 −0
Original line number Diff line number Diff line
@@ -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
#
+14 −0
Original line number Diff line number Diff line
@@ -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 *thd, Event_parse_data *parse_data,

  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;

+43 −1
Original line number Diff line number Diff line
@@ -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(THD *thd, my_time_t ltime_utc)
  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) {
@@ -141,6 +147,42 @@ Event_parse_data::check_if_in_the_past(THD *thd, my_time_t ltime_utc)
}


/*
  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.

+9 −1
Original line number Diff line number Diff line
@@ -38,7 +38,12 @@ class Event_parse_data : public Sql_alloc

  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 @@ class Event_parse_data : public Sql_alloc
  bool
  check_parse_data(THD *thd);

  bool
  check_dates(THD *thd, int previous_on_completion);

private:

  void
Loading