Commit 317c6851 authored by unknown's avatar unknown

fix for bug#16537 (Events: mysql.event.starts is null)

- now when the event is created and STARTS is omitted then STARTS is implicitly
  CURRENT_TIMESTAMP
- This CS also fixed incorrect presentation of STARTS/ENDS in I_S.EVENTS
(incorporated review changes)


mysql-test/r/events.result:
  results of new test cases
mysql-test/t/events.test:
  new test cases for bug #16537 (Events: mysql.event.starts is null)
sql/event.cc:
  - check whether event_timed::starts_null only in case
    event_timed::expression is set, so for recurring events only
  - disable binlogging of CREATE EVENT statement. It should not be
    replicated but the result of the execution. Still the replication is
    untouched topic.
sql/event.h:
  - add flags whether starts, ends and execute_at are null or not
sql/event_executor.cc:
  - check whether xxx_null instead of !xxxx.year
sql/event_timed.cc:
  - introduce xxx_null and change the usage of xxx.year to !xxx_null
sql/sql_show.cc:
  - don't show 0000-00-00 in I_S.EVENTS when the value is NULL
sql/sql_yacc.yy:
  - if STARTS is omitted default to current_timestamp
parent b9d41f5d
...@@ -13,6 +13,54 @@ alter event event3 rename to event2; ...@@ -13,6 +13,54 @@ alter event event3 rename to event2;
drop event event2; drop event event2;
create event event2 on schedule every 2 second starts now() ends date_add(now(), interval 5 hour) comment "some" DO begin end; create event event2 on schedule every 2 second starts now() ends date_add(now(), interval 5 hour) comment "some" DO begin end;
drop event event2; drop event event2;
CREATE EVENT event_starts_test ON SCHEDULE EVERY 10 SECOND COMMENT "" DO SELECT 1;
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost RECURRING NULL 10 INTERVAL_SECOND # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
0 1
ALTER EVENT event_starts_test ON SCHEDULE AT '2020-02-02 20:00:02';
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost ONE TIME 2020-02-02 17:00:02 NULL NULL # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
1 1
ALTER EVENT event_starts_test COMMENT "non-empty comment";
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost ONE TIME 2020-02-02 17:00:02 NULL NULL # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
1 1 non-empty comment
ALTER EVENT event_starts_test COMMENT "";
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost ONE TIME 2020-02-02 17:00:02 NULL NULL # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
1 1
DROP EVENT event_starts_test;
CREATE EVENT event_starts_test ON SCHEDULE EVERY 20 SECOND STARTS '2020-02-02 20:00:02' ENDS '2022-02-02 20:00:02' DO SELECT 2;
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost RECURRING NULL 20 INTERVAL_SECOND # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
0 0
ALTER EVENT event_starts_test COMMENT "non-empty comment";
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost RECURRING NULL 20 INTERVAL_SECOND # # ENABLED
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
starts IS NULL ends IS NULL comment
0 0 non-empty comment
ALTER EVENT event_starts_test COMMENT "";
SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost RECURRING NULL 20 INTERVAL_SECOND # # ENABLED
DROP EVENT event_starts_test;
create event e_43 on schedule every 1 second do set @a = 5; create event e_43 on schedule every 1 second do set @a = 5;
set global event_scheduler = 1; set global event_scheduler = 1;
select sleep(2); select sleep(2);
...@@ -64,7 +112,7 @@ SHOW GRANTS; ...@@ -64,7 +112,7 @@ SHOW GRANTS;
Grants for ev_test@localhost Grants for ev_test@localhost
GRANT USAGE ON *.* TO 'ev_test'@'localhost' GRANT USAGE ON *.* TO 'ev_test'@'localhost'
GRANT ALL PRIVILEGES ON `events_test`.* TO 'ev_test'@'localhost' GRANT ALL PRIVILEGES ON `events_test`.* TO 'ev_test'@'localhost'
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE ON `events_test2`.* TO 'ev_test'@'localhost' GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, TRIGGER ON `events_test2`.* TO 'ev_test'@'localhost'
"Here comes an error:"; "Here comes an error:";
SHOW EVENTS; SHOW EVENTS;
ERROR 42000: Access denied for user 'ev_test'@'localhost' to database 'events_test2' ERROR 42000: Access denied for user 'ev_test'@'localhost' to database 'events_test2'
......
...@@ -15,6 +15,38 @@ drop event event2; ...@@ -15,6 +15,38 @@ drop event event2;
create event event2 on schedule every 2 second starts now() ends date_add(now(), interval 5 hour) comment "some" DO begin end; create event event2 on schedule every 2 second starts now() ends date_add(now(), interval 5 hour) comment "some" DO begin end;
drop event event2; drop event event2;
# BUG #16537 (Events: mysql.event.starts is null)
CREATE EVENT event_starts_test ON SCHEDULE EVERY 10 SECOND COMMENT "" DO SELECT 1;
--replace_column 8 # 9 #
SHOW EVENTS;
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
ALTER EVENT event_starts_test ON SCHEDULE AT '2020-02-02 20:00:02';
--replace_column 8 # 9 #
SHOW EVENTS;
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
ALTER EVENT event_starts_test COMMENT "non-empty comment";
--replace_column 8 # 9 #
SHOW EVENTS;
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
ALTER EVENT event_starts_test COMMENT "";
--replace_column 8 # 9 #
SHOW EVENTS;
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
DROP EVENT event_starts_test;
CREATE EVENT event_starts_test ON SCHEDULE EVERY 20 SECOND STARTS '2020-02-02 20:00:02' ENDS '2022-02-02 20:00:02' DO SELECT 2;
--replace_column 8 # 9 #
SHOW EVENTS;
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
ALTER EVENT event_starts_test COMMENT "non-empty comment";
--replace_column 8 # 9 #
SHOW EVENTS;
SELECT starts IS NULL, ends IS NULL, comment FROM mysql.event WHERE db='events_test' AND name='event_starts_test';
ALTER EVENT event_starts_test COMMENT "";
--replace_column 8 # 9 #
SHOW EVENTS;
DROP EVENT event_starts_test;
#
#
create event e_43 on schedule every 1 second do set @a = 5; create event e_43 on schedule every 1 second do set @a = 5;
set global event_scheduler = 1; set global event_scheduler = 1;
select sleep(2); select sleep(2);
......
...@@ -273,20 +273,6 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update) ...@@ -273,20 +273,6 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
store(et->body.str, et->body.length, system_charset_info)) store(et->body.str, et->body.length, system_charset_info))
goto trunc_err; goto trunc_err;
if (et->starts.year)
{
table->field[EVEX_FIELD_STARTS]->set_notnull();// set NULL flag to OFF
table->field[EVEX_FIELD_STARTS]->
store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
}
if (et->ends.year)
{
table->field[EVEX_FIELD_ENDS]->set_notnull();
table->field[EVEX_FIELD_ENDS]->
store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
}
if (et->expression) if (et->expression)
{ {
table->field[EVEX_FIELD_INTERVAL_EXPR]->set_notnull(); table->field[EVEX_FIELD_INTERVAL_EXPR]->set_notnull();
...@@ -300,18 +286,31 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update) ...@@ -300,18 +286,31 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->store((longlong)et->interval+1); table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->store((longlong)et->interval+1);
table->field[EVEX_FIELD_EXECUTE_AT]->set_null(); table->field[EVEX_FIELD_EXECUTE_AT]->set_null();
if (!et->starts_null)
{
table->field[EVEX_FIELD_STARTS]->set_notnull();// set NULL flag to OFF
table->field[EVEX_FIELD_STARTS]->
store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
}
if (!et->ends_null)
{
table->field[EVEX_FIELD_ENDS]->set_notnull();
table->field[EVEX_FIELD_ENDS]->
store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
}
} }
else if (et->execute_at.year) else if (et->execute_at.year)
{ {
// fix_fields already called in init_execute_at
table->field[EVEX_FIELD_INTERVAL_EXPR]->set_null(); table->field[EVEX_FIELD_INTERVAL_EXPR]->set_null();
table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->set_null(); table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->set_null();
table->field[EVEX_FIELD_STARTS]->set_null();
table->field[EVEX_FIELD_ENDS]->set_null();
table->field[EVEX_FIELD_EXECUTE_AT]->set_notnull(); table->field[EVEX_FIELD_EXECUTE_AT]->set_notnull();
table->field[EVEX_FIELD_EXECUTE_AT]->store_time(&et->execute_at, table->field[EVEX_FIELD_EXECUTE_AT]->store_time(&et->execute_at,
MYSQL_TIMESTAMP_DATETIME); MYSQL_TIMESTAMP_DATETIME);
table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->set_null();
} }
else else
{ {
...@@ -322,14 +321,17 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update) ...@@ -322,14 +321,17 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
((Field_timestamp *)table->field[EVEX_FIELD_MODIFIED])->set_time(); ((Field_timestamp *)table->field[EVEX_FIELD_MODIFIED])->set_time();
if (et->comment.length) if (et->comment.str)
if (table->field[field_num= EVEX_FIELD_COMMENT]-> {
store(et->comment.str, et->comment.length, system_charset_info)) if (table->field[field_num= EVEX_FIELD_COMMENT]->store(et->comment.str,
et->comment.length,
system_charset_info))
goto trunc_err; goto trunc_err;
}
DBUG_RETURN(0); DBUG_RETURN(0);
trunc_err: trunc_err:
my_error(ER_EVENT_DATA_TOO_LONG, MYF(0)); my_error(ER_EVENT_DATA_TOO_LONG, MYF(0), table->field[field_num]->field_name);
DBUG_RETURN(EVEX_GENERAL_ERROR); DBUG_RETURN(EVEX_GENERAL_ERROR);
} }
...@@ -442,14 +444,16 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not, ...@@ -442,14 +444,16 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret); my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret);
goto err; goto err;
} }
#ifdef USE_THIS_CODE_AS_TEMPLATE_WHEN_EVENT_REPLICATION_IS_AGREED
if (mysql_bin_log.is_open()) if (mysql_bin_log.is_open())
{ {
thd->clear_error(); thd->clear_error();
/* Such a statement can always go directly to binlog, no trans cache */ // Such a statement can always go directly to binlog, no trans cache
thd->binlog_query(THD::MYSQL_QUERY_TYPE, thd->binlog_query(THD::MYSQL_QUERY_TYPE,
thd->query, thd->query_length, FALSE, FALSE); thd->query, thd->query_length, FALSE, FALSE);
} }
#endif
*rows_affected= 1; *rows_affected= 1;
ok: ok:
......
...@@ -100,6 +100,9 @@ class event_timed ...@@ -100,6 +100,9 @@ class event_timed
TIME starts; TIME starts;
TIME ends; TIME ends;
TIME execute_at; TIME execute_at;
my_bool starts_null;
my_bool ends_null;
my_bool execute_at_null;
longlong expression; longlong expression;
interval_type interval; interval_type interval;
......
...@@ -203,7 +203,7 @@ event_executor_main(void *arg) ...@@ -203,7 +203,7 @@ event_executor_main(void *arg)
if (init_event_thread(thd)) if (init_event_thread(thd))
goto err; goto err;
// make this thread invisible it has no vio -> show processlist won't see // make this thread invisible it has no vio -> show processlist won't see
thd->system_thread= 1; thd->system_thread= 1;
...@@ -321,8 +321,7 @@ event_executor_main(void *arg) ...@@ -321,8 +321,7 @@ event_executor_main(void *arg)
et= evex_queue_first_element(&EVEX_EQ_NAME, event_timed*); et= evex_queue_first_element(&EVEX_EQ_NAME, event_timed*);
DBUG_PRINT("evex main thread",("got event from the queue")); DBUG_PRINT("evex main thread",("got event from the queue"));
if (et->execute_at.year > 1969 && if (!et->execute_at_null && my_time_compare(&time_now,&et->execute_at) == -1)
my_time_compare(&time_now, &et->execute_at) == -1)
{ {
DBUG_PRINT("evex main thread",("still not the time for execution")); DBUG_PRINT("evex main thread",("still not the time for execution"));
VOID(pthread_mutex_unlock(&LOCK_event_arrays)); VOID(pthread_mutex_unlock(&LOCK_event_arrays));
...@@ -359,8 +358,11 @@ event_executor_main(void *arg) ...@@ -359,8 +358,11 @@ event_executor_main(void *arg)
#else #else
event_executor_worker((void *) et); event_executor_worker((void *) et);
#endif #endif
if ((et->execute_at.year && !et->expression) || /*
TIME_to_ulonglong_datetime(&et->execute_at) == 0) 1. For one-time event : year is > 0 and expression is 0
2. For recurring, expression is != -=> check execute_at_null in this case
*/
if ((et->execute_at.year && !et->expression) || et->execute_at_null)
et->flags |= EVENT_EXEC_NO_MORE; et->flags |= EVENT_EXEC_NO_MORE;
if ((et->flags & EVENT_EXEC_NO_MORE) || et->status == MYSQL_EVENT_DISABLED) if ((et->flags & EVENT_EXEC_NO_MORE) || et->status == MYSQL_EVENT_DISABLED)
...@@ -481,9 +483,9 @@ event_executor_worker(void *event_void) ...@@ -481,9 +483,9 @@ event_executor_worker(void *event_void)
#endif #endif
// thd->security_ctx->priv_host is char[MAX_HOSTNAME] // thd->security_ctx->priv_host is char[MAX_HOSTNAME]
strxnmov(thd->security_ctx->priv_host, sizeof(thd->security_ctx->priv_host), strxnmov(thd->security_ctx->priv_host, sizeof(thd->security_ctx->priv_host),
event->definer_host.str, NullS); event->definer_host.str, NullS);
thd->security_ctx->user= thd->security_ctx->priv_user= thd->security_ctx->user= thd->security_ctx->priv_user=
my_strdup(event->definer_user.str, MYF(0)); my_strdup(event->definer_user.str, MYF(0));
...@@ -506,7 +508,6 @@ event_executor_worker(void *event_void) ...@@ -506,7 +508,6 @@ event_executor_worker(void *event_void)
if (ret == EVEX_COMPILE_ERROR) if (ret == EVEX_COMPILE_ERROR)
sql_print_information(" EVEX COMPILE ERROR for event %s.%s", sql_print_information(" EVEX COMPILE ERROR for event %s.%s",
event->dbname.str, event->name.str); event->dbname.str, event->name.str);
DBUG_PRINT("info", (" EVEX EXECUTED event %s.%s [EXPR:%d]. RetCode=%d", DBUG_PRINT("info", (" EVEX EXECUTED event %s.%s [EXPR:%d]. RetCode=%d",
event->dbname.str, event->name.str, event->dbname.str, event->name.str,
(int) event->expression, ret)); (int) event->expression, ret));
......
This diff is collapsed.
...@@ -3883,35 +3883,32 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) ...@@ -3883,35 +3883,32 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
{ {
//type //type
sch_table->field[5]->store(STRING_WITH_LEN("RECURRING"), scs); sch_table->field[5]->store(STRING_WITH_LEN("RECURRING"), scs);
//execute_at
sch_table->field[6]->set_null();
//interval_value //interval_value
sch_table->field[7]->set_notnull(); sch_table->field[7]->set_notnull();
sch_table->field[7]->store((longlong) et.expression); sch_table->field[7]->store((longlong) et.expression);
//interval_type //interval_type
LEX_STRING *ival=&interval_type_to_name[get_real_interval_type(et.interval)]; LEX_STRING *ival=&interval_type_to_name[get_real_interval_type(et.interval)];
sch_table->field[8]->set_notnull(); sch_table->field[8]->set_notnull();
sch_table->field[8]->store(ival->str, ival->length, scs); sch_table->field[8]->store(ival->str, ival->length, scs);
//starts & ends
//starts & ends
sch_table->field[10]->set_notnull(); sch_table->field[10]->set_notnull();
sch_table->field[10]->store_time(&et.starts, MYSQL_TIMESTAMP_DATETIME); sch_table->field[10]->store_time(&et.starts, MYSQL_TIMESTAMP_DATETIME);
sch_table->field[11]->set_notnull();
sch_table->field[11]->store_time(&et.ends, MYSQL_TIMESTAMP_DATETIME); if (!et.ends_null)
{
sch_table->field[11]->set_notnull();
sch_table->field[11]->store_time(&et.ends, MYSQL_TIMESTAMP_DATETIME);
}
} }
else else
{ {
//type //type
sch_table->field[5]->store(STRING_WITH_LEN("ONE TIME"), scs); sch_table->field[5]->store(STRING_WITH_LEN("ONE TIME"), scs);
//execute_at
sch_table->field[6]->set_notnull(); sch_table->field[6]->set_notnull();
sch_table->field[6]->store_time(&et.execute_at, MYSQL_TIMESTAMP_DATETIME); sch_table->field[6]->store_time(&et.execute_at, MYSQL_TIMESTAMP_DATETIME);
//interval
sch_table->field[7]->set_null();
//interval_type
sch_table->field[8]->set_null();
//starts & ends
sch_table->field[10]->set_null();
sch_table->field[11]->set_null();
} }
//status //status
......
...@@ -1475,6 +1475,9 @@ opt_ev_status: /* empty */ {$<ulong_num>$= 0;} ...@@ -1475,6 +1475,9 @@ opt_ev_status: /* empty */ {$<ulong_num>$= 0;}
; ;
ev_starts: /* empty */ ev_starts: /* empty */
{
Lex->et->init_starts(YYTHD, new Item_func_now_local());
}
| STARTS_SYM expr | STARTS_SYM expr
{ {
LEX *lex= Lex; LEX *lex= Lex;
......
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