From 317c6851ba4acc75550f03e765de3a0eb1837ed0 Mon Sep 17 00:00:00 2001 From: unknown Date: Tue, 28 Feb 2006 11:43:10 +0100 Subject: [PATCH] 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 --- mysql-test/r/events.result | 50 +++++++++++++++- mysql-test/t/events.test | 32 ++++++++++ sql/event.cc | 52 +++++++++-------- sql/event.h | 3 + sql/event_executor.cc | 17 +++--- sql/event_timed.cc | 117 ++++++++++++++++++++++++------------- sql/sql_show.cc | 23 ++++---- sql/sql_yacc.yy | 3 + 8 files changed, 212 insertions(+), 85 deletions(-) diff --git a/mysql-test/r/events.result b/mysql-test/r/events.result index 41f944ab089..4aedf1f57af 100644 --- a/mysql-test/r/events.result +++ b/mysql-test/r/events.result @@ -13,6 +13,54 @@ alter event event3 rename to 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; 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; set global event_scheduler = 1; select sleep(2); @@ -64,7 +112,7 @@ SHOW GRANTS; Grants for ev_test@localhost GRANT USAGE ON *.* 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:"; SHOW EVENTS; ERROR 42000: Access denied for user 'ev_test'@'localhost' to database 'events_test2' diff --git a/mysql-test/t/events.test b/mysql-test/t/events.test index be24d490393..4f3f0455337 100644 --- a/mysql-test/t/events.test +++ b/mysql-test/t/events.test @@ -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; 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; set global event_scheduler = 1; select sleep(2); diff --git a/sql/event.cc b/sql/event.cc index abca622835a..a568a23758f 100644 --- a/sql/event.cc +++ b/sql/event.cc @@ -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)) 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) { 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) table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->store((longlong)et->interval+1); 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) { - // fix_fields already called in init_execute_at table->field[EVEX_FIELD_INTERVAL_EXPR]->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]->store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME); - - table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->set_null(); } else { @@ -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(); - if (et->comment.length) - if (table->field[field_num= EVEX_FIELD_COMMENT]-> - store(et->comment.str, et->comment.length, system_charset_info)) + if (et->comment.str) + { + if (table->field[field_num= EVEX_FIELD_COMMENT]->store(et->comment.str, + et->comment.length, + system_charset_info)) goto trunc_err; + } DBUG_RETURN(0); 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); } @@ -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); goto err; } - + +#ifdef USE_THIS_CODE_AS_TEMPLATE_WHEN_EVENT_REPLICATION_IS_AGREED if (mysql_bin_log.is_open()) { 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->query, thd->query_length, FALSE, FALSE); } +#endif *rows_affected= 1; ok: diff --git a/sql/event.h b/sql/event.h index 1fe5c8e5713..76f8cdecc0e 100644 --- a/sql/event.h +++ b/sql/event.h @@ -100,6 +100,9 @@ public: TIME starts; TIME ends; TIME execute_at; + my_bool starts_null; + my_bool ends_null; + my_bool execute_at_null; longlong expression; interval_type interval; diff --git a/sql/event_executor.cc b/sql/event_executor.cc index 7960f1e1758..3b01a0efb67 100644 --- a/sql/event_executor.cc +++ b/sql/event_executor.cc @@ -203,7 +203,7 @@ event_executor_main(void *arg) if (init_event_thread(thd)) goto err; - + // make this thread invisible it has no vio -> show processlist won't see thd->system_thread= 1; @@ -321,8 +321,7 @@ event_executor_main(void *arg) et= evex_queue_first_element(&EVEX_EQ_NAME, event_timed*); DBUG_PRINT("evex main thread",("got event from the queue")); - if (et->execute_at.year > 1969 && - my_time_compare(&time_now, &et->execute_at) == -1) + if (!et->execute_at_null && my_time_compare(&time_now,&et->execute_at) == -1) { DBUG_PRINT("evex main thread",("still not the time for execution")); VOID(pthread_mutex_unlock(&LOCK_event_arrays)); @@ -359,8 +358,11 @@ event_executor_main(void *arg) #else event_executor_worker((void *) et); #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; if ((et->flags & EVENT_EXEC_NO_MORE) || et->status == MYSQL_EVENT_DISABLED) @@ -481,9 +483,9 @@ event_executor_worker(void *event_void) #endif // thd->security_ctx->priv_host is char[MAX_HOSTNAME] - + 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= my_strdup(event->definer_user.str, MYF(0)); @@ -506,7 +508,6 @@ event_executor_worker(void *event_void) if (ret == EVEX_COMPILE_ERROR) sql_print_information(" EVEX COMPILE ERROR for event %s.%s", event->dbname.str, event->name.str); - DBUG_PRINT("info", (" EVEX EXECUTED event %s.%s [EXPR:%d]. RetCode=%d", event->dbname.str, event->name.str, (int) event->expression, ret)); diff --git a/sql/event_timed.cc b/sql/event_timed.cc index 28d21089b74..05be47cc005 100644 --- a/sql/event_timed.cc +++ b/sql/event_timed.cc @@ -41,6 +41,7 @@ event_timed::init() set_zero_time(&ends, MYSQL_TIMESTAMP_DATETIME); set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME); set_zero_time(&last_executed, MYSQL_TIMESTAMP_DATETIME); + starts_null= ends_null= execute_at_null= TRUE; definer_user.str= definer_host.str= 0; definer_user.length= definer_host.length= 0; @@ -141,14 +142,18 @@ event_timed::init_execute_at(THD *thd, Item *expr) { my_bool not_used; TIME ltime; - my_time_t my_time_tmp; TIME time_tmp; DBUG_ENTER("event_timed::init_execute_at"); if (expr->fix_fields(thd, &expr)) DBUG_RETURN(EVEX_PARSE_ERROR); - + + /* no starts and/or ends in case of execute_at */ + DBUG_PRINT("info", ("starts_null && ends_null should be 1 is %d", + (starts_null && ends_null))) + DBUG_ASSERT(starts_null && ends_null); + // let's check whether time is in the past thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, (my_time_t) thd->query_start()); @@ -161,14 +166,13 @@ event_timed::init_execute_at(THD *thd, Item *expr) TIME_to_ulonglong_datetime(&time_tmp)) DBUG_RETURN(EVEX_BAD_PARAMS); - /* This may result in a 1970-01-01 date if ltime is > 2037-xx-xx CONVERT_TZ has similar problem */ my_tz_UTC->gmt_sec_to_TIME(<ime, TIME_to_timestamp(thd,<ime, ¬_used)); - + execute_at_null= FALSE; execute_at= ltime; DBUG_RETURN(0); } @@ -303,7 +307,7 @@ event_timed::init_starts(THD *thd, Item *new_starts) if ((not_used= new_starts->get_date(<ime, TIME_NO_ZERO_DATE))) DBUG_RETURN(EVEX_BAD_PARAMS); - // let's check whether time is in the past + /* let's check whether time is in the past */ thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, (my_time_t) thd->query_start()); @@ -320,6 +324,7 @@ event_timed::init_starts(THD *thd, Item *new_starts) my_tz_UTC->gmt_sec_to_TIME(<ime, TIME_to_timestamp(thd, <ime, ¬_used)); starts= ltime; + starts_null= FALSE; DBUG_RETURN(0); } @@ -329,7 +334,7 @@ event_timed::init_starts(THD *thd, Item *new_starts) SYNOPSIS event_timed::init_ends() - thd THD + thd THD new_ends when? NOTES @@ -342,15 +347,14 @@ event_timed::init_starts(THD *thd, Item *new_starts) RETURNS 0 - OK - EVEX_PARSE_ERROR - fix_fields failed - EVEX_BAD_PARAMS - ENDS before STARTS + EVEX_PARSE_ERROR fix_fields failed + EVEX_BAD_PARAMS ENDS before STARTS */ int event_timed::init_ends(THD *thd, Item *new_ends) { - TIME ltime; - my_time_t my_time_tmp; + TIME ltime, ltime_now; my_bool not_used; DBUG_ENTER("event_timed::init_ends"); @@ -358,20 +362,34 @@ event_timed::init_ends(THD *thd, Item *new_ends) if (new_ends->fix_fields(thd, &new_ends)) DBUG_RETURN(EVEX_PARSE_ERROR); - // the field was already fixed in init_ends + DBUG_PRINT("info", ("convert to TIME")); if ((not_used= new_ends->get_date(<ime, TIME_NO_ZERO_DATE))) DBUG_RETURN(EVEX_BAD_PARAMS); /* - This may result in a 1970-01-01 date if ltime is > 2037-xx-xx - CONVERT_TZ has similar problem + This may result in a 1970-01-01 date if ltime is > 2037-xx-xx ? + CONVERT_TZ has similar problem ? */ + DBUG_PRINT("info", ("get the UTC time")); my_tz_UTC->gmt_sec_to_TIME(<ime, TIME_to_timestamp(thd, <ime, ¬_used)); - - if (starts.year && my_time_compare(&starts, <ime) != -1) + + /* Check whether ends is after starts */ + DBUG_PRINT("info", ("ENDS after STARTS?")); + if (!starts_null && my_time_compare(&starts, <ime) != -1) + DBUG_RETURN(EVEX_BAD_PARAMS); + + /* + The parser forces starts to be provided but one day STARTS could be + set before NOW() and in this case the following check should be done. + Check whether ENDS is not in the past. + */ + DBUG_PRINT("info", ("ENDS after NOW?")); + my_tz_UTC->gmt_sec_to_TIME(<ime_now, thd->query_start()); + if (my_time_compare(<ime_now, <ime) == 1) DBUG_RETURN(EVEX_BAD_PARAMS); ends= ltime; + ends_null= FALSE; DBUG_RETURN(0); } @@ -391,7 +409,7 @@ event_timed::init_comment(THD *thd, LEX_STRING *set_comment) DBUG_ENTER("event_timed::init_comment"); comment.str= strmake_root(thd->mem_root, set_comment->str, - comment.length= set_comment->length); + comment.length= set_comment->length); DBUG_VOID_RETURN; } @@ -498,28 +516,37 @@ event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table) et->definer_host.str= strmake_root(mem_root, ptr + 1, len);//1: because of @ et->definer_host.length= len; - res1= table->field[EVEX_FIELD_STARTS]-> - get_date(&et->starts, TIME_NO_ZERO_DATE); + et->starts_null= table->field[EVEX_FIELD_STARTS]->is_null(); + res1= table->field[EVEX_FIELD_STARTS]->get_date(&et->starts,TIME_NO_ZERO_DATE); - res2= table->field[EVEX_FIELD_ENDS]-> - get_date(&et->ends, TIME_NO_ZERO_DATE); + et->ends_null= table->field[EVEX_FIELD_ENDS]->is_null(); + res2= table->field[EVEX_FIELD_ENDS]->get_date(&et->ends, TIME_NO_ZERO_DATE); - et->expression= table->field[EVEX_FIELD_INTERVAL_EXPR]->val_int(); - + if (!table->field[EVEX_FIELD_INTERVAL_EXPR]->is_null()) + et->expression= table->field[EVEX_FIELD_INTERVAL_EXPR]->val_int(); + else + et->expression= 0; /* If res1 and res2 are true then both fields are empty. Hence if EVEX_FIELD_EXECUTE_AT is empty there is an error. */ - if (res1 && res2 && !et->expression && table->field[EVEX_FIELD_EXECUTE_AT]-> - get_date(&et->execute_at, TIME_NO_ZERO_DATE)) + et->execute_at_null= table->field[EVEX_FIELD_EXECUTE_AT]->is_null(); + DBUG_ASSERT(!(et->starts_null && et->ends_null && !et->expression && + et->execute_at_null)); + if (!et->expression && + table->field[EVEX_FIELD_EXECUTE_AT]->get_date(&et->execute_at, + TIME_NO_ZERO_DATE)) goto error; /* In DB the values start from 1 but enum interval_type starts from 0 */ - et->interval= (interval_type) + if (!table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->is_null()) + et->interval= (interval_type) ((ulonglong) table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->val_int() - 1); + else + et->interval= (interval_type) 0; et->modified= table->field[EVEX_FIELD_CREATED]->val_int(); et->created= table->field[EVEX_FIELD_MODIFIED]->val_int(); @@ -676,14 +703,11 @@ event_timed::compute_next_execution_time() //let's check whether it was executed if (last_executed.year) { - DBUG_PRINT("compute_next_execution_time", - ("One-time event %s was already executed", name.str)); - if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP) - { - DBUG_PRINT("compute_next_execution_time", - ("One-time event will be dropped.")); - dropped= true; - } + DBUG_PRINT("info",("One-time event %s.%s of was already executed", + dbname.str, name.str, definer.str)); + dropped= (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP); + DBUG_PRINT("info",("One-time event will be dropped=%d.", dropped)); + status= MYSQL_EVENT_DISABLED; status_changed= true; } @@ -710,10 +734,11 @@ event_timed::compute_next_execution_time() #endif //if time_now is after ends don't execute anymore - if (ends.year && (tmp= my_time_compare(&ends, &time_now)) == -1) + if (!ends_null && (tmp= my_time_compare(&ends, &time_now)) == -1) { // time_now is after ends. don't execute anymore set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME); + execute_at_null= TRUE; if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP) dropped= true; status= MYSQL_EVENT_DISABLED; @@ -727,7 +752,7 @@ event_timed::compute_next_execution_time() Let's check whether time_now is before starts. If so schedule for starts */ - if (starts.year && (tmp= my_time_compare(&time_now, &starts)) < 1) + if (!starts_null && (tmp= my_time_compare(&time_now, &starts)) < 1) { if (tmp == 0 && my_time_compare(&starts, &last_executed) == 0) { @@ -743,11 +768,12 @@ event_timed::compute_next_execution_time() time_now before starts. Scheduling for starts */ execute_at= starts; + execute_at_null= FALSE; goto ret; } } - if (starts.year && ends.year) + if (!starts_null && !ends_null) { /* Both starts and m_ends are set and time_now is between them (incl.) @@ -756,7 +782,10 @@ event_timed::compute_next_execution_time() If not set then schedule for now. */ if (!last_executed.year) + { execute_at= time_now; + execute_at_null= FALSE; + } else { TIME next_exec; @@ -769,15 +798,19 @@ event_timed::compute_next_execution_time() { // Next execution after ends. No more executions set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME); + execute_at_null= TRUE; if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP) dropped= true; } else + { execute_at= next_exec; + execute_at_null= FALSE; + } } goto ret; } - else if (!starts.year && !ends.year) + else if (starts_null && ends_null) { // both starts and m_ends are not set, se we schedule for the next // based on last_executed @@ -789,11 +822,12 @@ event_timed::compute_next_execution_time() else //last_executed not set. Schedule the event for now execute_at= time_now; + execute_at_null= FALSE; } else { //either starts or m_ends is set - if (starts.year) + if (!starts_null) { /* - starts is set. @@ -808,6 +842,7 @@ event_timed::compute_next_execution_time() } else execute_at= starts; + execute_at_null= FALSE; } else { @@ -830,11 +865,15 @@ event_timed::compute_next_execution_time() if (my_time_compare(&ends, &next_exec) == -1) { set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME); + execute_at_null= TRUE; if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP) dropped= true; } else + { execute_at= next_exec; + execute_at_null= FALSE; + } } } goto ret; @@ -1025,7 +1064,7 @@ event_timed::execute(THD *thd, MEM_ROOT *mem_root) if (!sphead && (ret= compile(thd, mem_root))) goto done; - + ret= sphead->execute_procedure(thd, &empty_item_list); VOID(pthread_mutex_lock(&this->LOCK_running)); diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 7a1d843dd45..f78796bfcfb 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -3883,35 +3883,32 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) { //type sch_table->field[5]->store(STRING_WITH_LEN("RECURRING"), scs); - //execute_at - sch_table->field[6]->set_null(); //interval_value sch_table->field[7]->set_notnull(); sch_table->field[7]->store((longlong) et.expression); + //interval_type LEX_STRING *ival=&interval_type_to_name[get_real_interval_type(et.interval)]; sch_table->field[8]->set_notnull(); sch_table->field[8]->store(ival->str, ival->length, scs); - //starts & ends + + //starts & ends sch_table->field[10]->set_notnull(); 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 { //type sch_table->field[5]->store(STRING_WITH_LEN("ONE TIME"), scs); - //execute_at + sch_table->field[6]->set_notnull(); 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 diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 79651f2e49e..b59d5f9d70d 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1475,6 +1475,9 @@ opt_ev_status: /* empty */ {$$= 0;} ; ev_starts: /* empty */ + { + Lex->et->init_starts(YYTHD, new Item_func_now_local()); + } | STARTS_SYM expr { LEX *lex= Lex;