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

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
...@@ -328,4 +328,81 @@ create event ...@@ -328,4 +328,81 @@ create event
очень_очень_очень_очень_очень_очень_очень_очень_длинная_строка_66 очень_очень_очень_очень_очень_очень_очень_очень_длинная_строка_66
on schedule every 2 year do select 1; on schedule every 2 year do select 1;
ERROR 42000: Identifier name 'очень_очень_очень_очень_очень_очень_очень_очень_длинна' is too long 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; drop database events_test;
...@@ -411,6 +411,108 @@ create event ...@@ -411,6 +411,108 @@ create event
очень_очень_очень_очень_очень_очень_очень_очень_длинная_строка_66 очень_очень_очень_очень_очень_очень_очень_очень_длинная_строка_66
on schedule every 2 year do select 1; 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 # End of tests
# #
......
...@@ -185,6 +185,8 @@ mysql_event_fill_row(THD *thd, ...@@ -185,6 +185,8 @@ mysql_event_fill_row(THD *thd,
DBUG_PRINT("info", ("dbname=[%s]", et->dbname.str)); DBUG_PRINT("info", ("dbname=[%s]", et->dbname.str));
DBUG_PRINT("info", ("name =[%s]", et->name.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) if (table->s->fields < ET_FIELD_COUNT)
{ {
/* /*
...@@ -745,6 +747,18 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data, ...@@ -745,6 +747,18 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
store_record(table,record[1]); 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. */ /* Don't update create on row update. */
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
......
...@@ -45,7 +45,7 @@ Event_parse_data::new_instance(THD *thd) ...@@ -45,7 +45,7 @@ Event_parse_data::new_instance(THD *thd)
*/ */
Event_parse_data::Event_parse_data() 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), status(Event_parse_data::ENABLED),
do_not_create(FALSE), do_not_create(FALSE),
body_changed(FALSE), body_changed(FALSE),
...@@ -114,6 +114,12 @@ Event_parse_data::check_if_in_the_past(THD *thd, my_time_t ltime_utc) ...@@ -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()) if (ltime_utc >= (my_time_t) thd->query_start())
return; 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) if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
{ {
switch (thd->lex->sql_command) { switch (thd->lex->sql_command) {
...@@ -141,6 +147,42 @@ Event_parse_data::check_if_in_the_past(THD *thd, my_time_t ltime_utc) ...@@ -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. Sets time for execution for one-time event.
......
...@@ -38,7 +38,12 @@ public: ...@@ -38,7 +38,12 @@ public:
enum enum_on_completion 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 ON_COMPLETION_PRESERVE
}; };
...@@ -80,6 +85,9 @@ public: ...@@ -80,6 +85,9 @@ public:
bool bool
check_parse_data(THD *thd); check_parse_data(THD *thd);
bool
check_dates(THD *thd, int previous_on_completion);
private: private:
void void
......
...@@ -1786,6 +1786,8 @@ event_tail: ...@@ -1786,6 +1786,8 @@ event_tail:
if (!(lex->event_parse_data= Event_parse_data::new_instance(thd))) if (!(lex->event_parse_data= Event_parse_data::new_instance(thd)))
MYSQL_YYABORT; MYSQL_YYABORT;
lex->event_parse_data->identifier= $3; 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 We have to turn of CLIENT_MULTI_QUERIES while parsing a
......
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