Merge ahristov@bk-internal.mysql.com:/home/bk/mysql-5.1-new
into lmy004.:/work/mysql-5.1-bug16537
This commit is contained in:
commit
79298b3e77
@ -37,6 +37,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 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 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 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 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;
|
||||||
alter event e_43 do alter event e_43 do set @a = 4;
|
alter event e_43 do alter event e_43 do set @a = 4;
|
||||||
|
@ -48,6 +48,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;
|
||||||
--sleep 2
|
--sleep 2
|
||||||
|
90
sql/event.cc
90
sql/event.cc
@ -120,6 +120,7 @@ static TABLE_FIELD_W_TYPE event_table_fields[EVEX_FIELD_COUNT] = {
|
|||||||
{
|
{
|
||||||
{(char *) STRING_WITH_LEN("last_executed")},
|
{(char *) STRING_WITH_LEN("last_executed")},
|
||||||
{(char *) STRING_WITH_LEN("datetime")},
|
{(char *) STRING_WITH_LEN("datetime")},
|
||||||
|
{NULL, 0}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
{(char *) STRING_WITH_LEN("starts")},
|
{(char *) STRING_WITH_LEN("starts")},
|
||||||
@ -343,8 +344,6 @@ event_timed_compare_q(void *vptr, byte* a, byte *b)
|
|||||||
RETURNS
|
RETURNS
|
||||||
0 - OK
|
0 - OK
|
||||||
1 - Error
|
1 - Error
|
||||||
|
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -619,7 +618,7 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
|
|||||||
store(et->name.str, et->name.length, system_charset_info))
|
store(et->name.str, et->name.length, system_charset_info))
|
||||||
goto trunc_err;
|
goto trunc_err;
|
||||||
|
|
||||||
// both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()
|
/* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull() */
|
||||||
table->field[EVEX_FIELD_ON_COMPLETION]->store((longlong)et->on_completion);
|
table->field[EVEX_FIELD_ON_COMPLETION]->store((longlong)et->on_completion);
|
||||||
|
|
||||||
table->field[EVEX_FIELD_STATUS]->store((longlong)et->status);
|
table->field[EVEX_FIELD_STATUS]->store((longlong)et->status);
|
||||||
@ -637,20 +636,6 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update)
|
|||||||
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();
|
||||||
@ -664,36 +649,54 @@ 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();
|
||||||
|
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
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(is_update);
|
DBUG_ASSERT(is_update);
|
||||||
// it is normal to be here when the action is update
|
/*
|
||||||
// this is an error if the action is create. something is borked
|
it is normal to be here when the action is update
|
||||||
|
this is an error if the action is create. something is borked
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
((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);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -797,7 +800,10 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
|
|||||||
|
|
||||||
((Field_timestamp *)table->field[EVEX_FIELD_CREATED])->set_time();
|
((Field_timestamp *)table->field[EVEX_FIELD_CREATED])->set_time();
|
||||||
|
|
||||||
// evex_fill_row() calls my_error() in case of error so no need to handle it here
|
/*
|
||||||
|
evex_fill_row() calls my_error() in case of error so no need to
|
||||||
|
handle it here
|
||||||
|
*/
|
||||||
if ((ret= evex_fill_row(thd, table, et, false)))
|
if ((ret= evex_fill_row(thd, table, et, false)))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
@ -807,6 +813,7 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
|
|||||||
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();
|
||||||
@ -814,6 +821,7 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not,
|
|||||||
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:
|
||||||
@ -865,7 +873,7 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// first look whether we overwrite
|
/* first look whether we overwrite */
|
||||||
if (new_name)
|
if (new_name)
|
||||||
{
|
{
|
||||||
if (!sortcmp_lex_string(et->name, new_name->m_name, system_charset_info) &&
|
if (!sortcmp_lex_string(et->name, new_name->m_name, system_charset_info) &&
|
||||||
@ -894,13 +902,12 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
store_record(table,record[1]);
|
store_record(table,record[1]);
|
||||||
|
|
||||||
// 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;
|
||||||
|
|
||||||
// evex_fill_row() calls my_error() in case of error so no need to handle it here
|
/* evex_fill_row() calls my_error() in case of error so no need to handle it here */
|
||||||
if ((ret= evex_fill_row(thd, table, et, true)))
|
if ((ret= evex_fill_row(thd, table, et, true)))
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
@ -918,7 +925,7 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name)
|
|||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
// close mysql.event or we crash later when loading the event from disk
|
/* close mysql.event or we crash later when loading the event from disk */
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
@ -995,7 +1002,7 @@ done:
|
|||||||
delete et;
|
delete et;
|
||||||
et= 0;
|
et= 0;
|
||||||
}
|
}
|
||||||
// don't close the table if we haven't opened it ourselves
|
/* don't close the table if we haven't opened it ourselves */
|
||||||
if (!tbl && table)
|
if (!tbl && table)
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
*ett= et;
|
*ett= et;
|
||||||
@ -1017,7 +1024,6 @@ done:
|
|||||||
RETURN VALUE
|
RETURN VALUE
|
||||||
0 - OK
|
0 - OK
|
||||||
< 0 - error (in this case underlying functions call my_error()).
|
< 0 - error (in this case underlying functions call my_error()).
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -1036,7 +1042,7 @@ evex_load_and_compile_event(THD * thd, sp_name *spn, LEX_STRING definer,
|
|||||||
thd->mem_root= &evex_mem_root;
|
thd->mem_root= &evex_mem_root;
|
||||||
|
|
||||||
thd->reset_n_backup_open_tables_state(&backup);
|
thd->reset_n_backup_open_tables_state(&backup);
|
||||||
// no need to use my_error() here because db_find_event() has done it
|
/* no need to use my_error() here because db_find_event() has done it */
|
||||||
ret= db_find_event(thd, spn, &definer, &ett, NULL, NULL);
|
ret= db_find_event(thd, spn, &definer, &ett, NULL, NULL);
|
||||||
thd->restore_backup_open_tables_state(&backup);
|
thd->restore_backup_open_tables_state(&backup);
|
||||||
if (ret)
|
if (ret)
|
||||||
@ -1088,7 +1094,7 @@ done:
|
|||||||
ALTER EVENT.
|
ALTER EVENT.
|
||||||
|
|
||||||
RETURNS
|
RETURNS
|
||||||
0 - OK (always)
|
0 OK (always)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -1131,7 +1137,7 @@ evex_remove_from_cache(LEX_STRING *db, LEX_STRING *name, bool use_lock,
|
|||||||
}
|
}
|
||||||
DBUG_PRINT("evex_remove_from_cache", ("delete from queue"));
|
DBUG_PRINT("evex_remove_from_cache", ("delete from queue"));
|
||||||
evex_queue_delete_element(&EVEX_EQ_NAME, i);
|
evex_queue_delete_element(&EVEX_EQ_NAME, i);
|
||||||
// ok, we have cleaned
|
/* ok, we have cleaned */
|
||||||
ret= 0;
|
ret= 0;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
@ -1185,7 +1191,7 @@ evex_create_event(THD *thd, event_timed *et, uint create_options,
|
|||||||
VOID(pthread_mutex_unlock(&LOCK_evex_running));
|
VOID(pthread_mutex_unlock(&LOCK_evex_running));
|
||||||
|
|
||||||
done:
|
done:
|
||||||
// No need to close the table, it will be closed in sql_parse::do_command
|
/* No need to close the table, it will be closed in sql_parse::do_command */
|
||||||
|
|
||||||
DBUG_RETURN(ret);
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
@ -1259,7 +1265,6 @@ done:
|
|||||||
et event's name
|
et event's name
|
||||||
drop_if_exists if set and the event not existing => warning onto the stack
|
drop_if_exists if set and the event not existing => warning onto the stack
|
||||||
rows_affected affected number of rows is returned heres
|
rows_affected affected number of rows is returned heres
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int db_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
|
int db_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
|
||||||
@ -1362,7 +1367,6 @@ evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists,
|
|||||||
RETURNS
|
RETURNS
|
||||||
0 - OK
|
0 - OK
|
||||||
1 - Error during writing to the wire
|
1 - Error during writing to the wire
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -1413,7 +1417,6 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
|
|||||||
|
|
||||||
protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
|
protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
|
||||||
|
|
||||||
|
|
||||||
protocol->store(show_str.c_ptr(), show_str.length(), system_charset_info);
|
protocol->store(show_str.c_ptr(), show_str.length(), system_charset_info);
|
||||||
ret= protocol->write();
|
ret= protocol->write();
|
||||||
send_eof(thd);
|
send_eof(thd);
|
||||||
@ -1449,7 +1452,6 @@ evex_show_create_event(THD *thd, sp_name *spn, LEX_STRING definer)
|
|||||||
spawned and can_spawn() is the right method.
|
spawned and can_spawn() is the right method.
|
||||||
- event_timed::can_spawn() returns false -> being runned ATM
|
- event_timed::can_spawn() returns false -> being runned ATM
|
||||||
just set the flags so it should drop itself.
|
just set the flags so it should drop itself.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
@ -1521,7 +1523,7 @@ evex_drop_db_events(THD *thd, char *db)
|
|||||||
}
|
}
|
||||||
DBUG_PRINT("info",("%d elements in the queue",
|
DBUG_PRINT("info",("%d elements in the queue",
|
||||||
evex_queue_num_elements(EVEX_EQ_NAME)));
|
evex_queue_num_elements(EVEX_EQ_NAME)));
|
||||||
evex_queue_delete_element(&EVEX_EQ_NAME, i);// 1 is top
|
evex_queue_delete_element(&EVEX_EQ_NAME, i);// 0 is top
|
||||||
DBUG_PRINT("info",("%d elements in the queue",
|
DBUG_PRINT("info",("%d elements in the queue",
|
||||||
evex_queue_num_elements(EVEX_EQ_NAME)));
|
evex_queue_num_elements(EVEX_EQ_NAME)));
|
||||||
/*
|
/*
|
||||||
@ -1598,7 +1600,7 @@ end:
|
|||||||
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
|
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
|
||||||
end_read_record(&read_record_info);
|
end_read_record(&read_record_info);
|
||||||
|
|
||||||
thd->version--; // Force close to free memory
|
thd->version--; /* Force close to free memory */
|
||||||
|
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
|
|
||||||
|
@ -103,6 +103,9 @@ public:
|
|||||||
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;
|
||||||
|
@ -135,7 +135,7 @@ evex_check_system_tables()
|
|||||||
bool not_used;
|
bool not_used;
|
||||||
Open_tables_state backup;
|
Open_tables_state backup;
|
||||||
|
|
||||||
// thd is 0x0 during boot of the server. Later it's !=0x0
|
/* thd is 0x0 during boot of the server. Later it's !=0x0 */
|
||||||
if (!thd)
|
if (!thd)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -206,7 +206,7 @@ init_events()
|
|||||||
if (event_executor_running_global_var)
|
if (event_executor_running_global_var)
|
||||||
{
|
{
|
||||||
#ifndef DBUG_FAULTY_THR
|
#ifndef DBUG_FAULTY_THR
|
||||||
//TODO Andrey: Change the error code returned!
|
/* TODO Andrey: Change the error code returned! */
|
||||||
if (pthread_create(&th, &connection_attrib, event_executor_main,(void*)NULL))
|
if (pthread_create(&th, &connection_attrib, event_executor_main,(void*)NULL))
|
||||||
DBUG_RETURN(ER_SLAVE_THREAD);
|
DBUG_RETURN(ER_SLAVE_THREAD);
|
||||||
#else
|
#else
|
||||||
@ -339,14 +339,14 @@ executor_wait_till_next_event_exec(THD *thd)
|
|||||||
if (et->dropped)
|
if (et->dropped)
|
||||||
et->drop(thd);
|
et->drop(thd);
|
||||||
delete et;
|
delete et;
|
||||||
evex_queue_delete_element(&EVEX_EQ_NAME, 1);// 1 is top
|
evex_queue_delete_element(&EVEX_EQ_NAME, 0);// 0 is top, internally 1
|
||||||
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
|
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
|
||||||
sql_print_information("Event found disabled, dropping.");
|
sql_print_information("Event found disabled, dropping.");
|
||||||
DBUG_RETURN(1);
|
DBUG_RETURN(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBUG_PRINT("evex main thread",("computing time to sleep till next exec"));
|
DBUG_PRINT("evex main thread",("computing time to sleep till next exec"));
|
||||||
// set the internal clock of thd
|
/* set the internal clock of thd */
|
||||||
thd->end_time();
|
thd->end_time();
|
||||||
my_tz_UTC->gmt_sec_to_TIME(&time_now, thd->query_start());
|
my_tz_UTC->gmt_sec_to_TIME(&time_now, thd->query_start());
|
||||||
t2sleep= evex_time_diff(&et->execute_at, &time_now);
|
t2sleep= evex_time_diff(&et->execute_at, &time_now);
|
||||||
@ -387,7 +387,7 @@ executor_wait_till_next_event_exec(THD *thd)
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
event_executor_main()
|
event_executor_main()
|
||||||
arg - unused
|
arg unused
|
||||||
|
|
||||||
NOTES
|
NOTES
|
||||||
1. The host of the thead is my_localhost
|
1. The host of the thead is my_localhost
|
||||||
@ -407,11 +407,10 @@ event_executor_main(void *arg)
|
|||||||
DBUG_PRINT("event_executor_main", ("EVEX thread started"));
|
DBUG_PRINT("event_executor_main", ("EVEX thread started"));
|
||||||
|
|
||||||
|
|
||||||
// init memory root
|
/* init memory root */
|
||||||
init_alloc_root(&evex_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
|
init_alloc_root(&evex_mem_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
|
||||||
|
|
||||||
|
/* needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff*/
|
||||||
// needs to call my_thread_init(), otherwise we get a coredump in DBUG_ stuff
|
|
||||||
my_thread_init();
|
my_thread_init();
|
||||||
|
|
||||||
if (sizeof(my_time_t) != sizeof(time_t))
|
if (sizeof(my_time_t) != sizeof(time_t))
|
||||||
@ -422,8 +421,8 @@ event_executor_main(void *arg)
|
|||||||
goto err_no_thd;
|
goto err_no_thd;
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO Andrey: Check for NULL
|
/* note that contructor of THD uses DBUG_ ! */
|
||||||
if (!(thd = new THD)) // note that contructor of THD uses DBUG_ !
|
if (!(thd = new THD))
|
||||||
{
|
{
|
||||||
sql_print_error("SCHEDULER: Cannot create THD for the main thread.");
|
sql_print_error("SCHEDULER: Cannot create THD for the main thread.");
|
||||||
goto err_no_thd;
|
goto err_no_thd;
|
||||||
@ -523,8 +522,7 @@ restart_ticking:
|
|||||||
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));
|
||||||
@ -571,8 +569,11 @@ restart_ticking:
|
|||||||
#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)
|
||||||
@ -582,10 +583,10 @@ restart_ticking:
|
|||||||
}
|
}
|
||||||
DBUG_PRINT("evex main thread",("unlocking"));
|
DBUG_PRINT("evex main thread",("unlocking"));
|
||||||
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
|
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
|
||||||
}// while
|
}/* while */
|
||||||
finish:
|
finish:
|
||||||
|
|
||||||
// First manifest that this thread does not work and then destroy
|
/* First manifest that this thread does not work and then destroy */
|
||||||
VOID(pthread_mutex_lock(&LOCK_evex_running));
|
VOID(pthread_mutex_lock(&LOCK_evex_running));
|
||||||
evex_is_running= false;
|
evex_is_running= false;
|
||||||
evex_main_thread_id= 0;
|
evex_main_thread_id= 0;
|
||||||
@ -625,7 +626,7 @@ finish:
|
|||||||
delete et;
|
delete et;
|
||||||
}
|
}
|
||||||
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
|
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
|
||||||
// ... then we can thrash the whole queue at once
|
/* ... then we can thrash the whole queue at once */
|
||||||
evex_queue_destroy(&EVEX_EQ_NAME);
|
evex_queue_destroy(&EVEX_EQ_NAME);
|
||||||
|
|
||||||
thd->proc_info = "Clearing";
|
thd->proc_info = "Clearing";
|
||||||
@ -665,7 +666,7 @@ err_no_thd:
|
|||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
event_executor_worker()
|
event_executor_worker()
|
||||||
arg - the event_timed object to be processed
|
arg The event_timed object to be processed
|
||||||
*/
|
*/
|
||||||
|
|
||||||
pthread_handler_t
|
pthread_handler_t
|
||||||
@ -682,7 +683,7 @@ event_executor_worker(void *event_void)
|
|||||||
#ifndef DBUG_FAULTY_THR
|
#ifndef DBUG_FAULTY_THR
|
||||||
my_thread_init();
|
my_thread_init();
|
||||||
|
|
||||||
if (!(thd = new THD)) // note that contructor of THD uses DBUG_ !
|
if (!(thd = new THD)) /* note that contructor of THD uses DBUG_ ! */
|
||||||
{
|
{
|
||||||
sql_print_error("SCHEDULER: Cannot create a THD structure in an worker.");
|
sql_print_error("SCHEDULER: Cannot create a THD structure in an worker.");
|
||||||
goto err_no_thd;
|
goto err_no_thd;
|
||||||
@ -697,7 +698,7 @@ event_executor_worker(void *event_void)
|
|||||||
|
|
||||||
thd->init_for_queries();
|
thd->init_for_queries();
|
||||||
|
|
||||||
// make this thread visible it has no vio -> show processlist needs this flag
|
/* make this thread visible it has no vio -> show processlist needs this flag */
|
||||||
thd->system_thread= 1;
|
thd->system_thread= 1;
|
||||||
|
|
||||||
VOID(pthread_mutex_lock(&LOCK_thread_count));
|
VOID(pthread_mutex_lock(&LOCK_thread_count));
|
||||||
@ -778,8 +779,8 @@ err_no_thd:
|
|||||||
thd - Thread context. Used for memory allocation in some cases.
|
thd - Thread context. Used for memory allocation in some cases.
|
||||||
|
|
||||||
RETURNS
|
RETURNS
|
||||||
0 - OK
|
0 OK
|
||||||
!0 - Error
|
!0 Error
|
||||||
|
|
||||||
NOTES
|
NOTES
|
||||||
Reports the error to the console
|
Reports the error to the console
|
||||||
@ -845,7 +846,7 @@ evex_load_events_from_db(THD *thd)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// let's find when to be executed
|
/* let's find when to be executed */
|
||||||
if (et->compute_next_execution_time())
|
if (et->compute_next_execution_time())
|
||||||
{
|
{
|
||||||
sql_print_error("SCHEDULER: Error while computing execution time of %s.%s."
|
sql_print_error("SCHEDULER: Error while computing execution time of %s.%s."
|
||||||
@ -867,7 +868,8 @@ end:
|
|||||||
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
|
VOID(pthread_mutex_unlock(&LOCK_event_arrays));
|
||||||
end_read_record(&read_record_info);
|
end_read_record(&read_record_info);
|
||||||
|
|
||||||
thd->version--; // Force close to free memory
|
/* Force close to free memory */
|
||||||
|
thd->version--;
|
||||||
|
|
||||||
close_thread_tables(thd);
|
close_thread_tables(thd);
|
||||||
if (!ret)
|
if (!ret)
|
||||||
@ -889,13 +891,13 @@ end:
|
|||||||
car - the new value
|
car - the new value
|
||||||
|
|
||||||
Returns
|
Returns
|
||||||
0 - OK (always)
|
0 OK (always)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
sys_var_event_executor::update(THD *thd, set_var *var)
|
sys_var_event_executor::update(THD *thd, set_var *var)
|
||||||
{
|
{
|
||||||
// here start the thread if not running.
|
/* here start the thread if not running. */
|
||||||
DBUG_ENTER("sys_var_event_executor::update");
|
DBUG_ENTER("sys_var_event_executor::update");
|
||||||
VOID(pthread_mutex_lock(&LOCK_evex_running));
|
VOID(pthread_mutex_lock(&LOCK_evex_running));
|
||||||
*value= var->save_result.ulong_value;
|
*value= var->save_result.ulong_value;
|
||||||
@ -952,7 +954,8 @@ evex_print_warnings(THD *thd, event_timed *et)
|
|||||||
while ((err= it++))
|
while ((err= it++))
|
||||||
{
|
{
|
||||||
String err_msg(msg_buf, sizeof(msg_buf), system_charset_info);
|
String err_msg(msg_buf, sizeof(msg_buf), system_charset_info);
|
||||||
err_msg.length(0);// set it to 0 or we start adding at the end
|
/* set it to 0 or we start adding at the end. That's the trick ;) */
|
||||||
|
err_msg.length(0);
|
||||||
if (!prefix.length())
|
if (!prefix.length())
|
||||||
{
|
{
|
||||||
prefix.append("SCHEDULER: [");
|
prefix.append("SCHEDULER: [");
|
||||||
|
@ -41,6 +41,7 @@ event_timed::init()
|
|||||||
set_zero_time(&ends, MYSQL_TIMESTAMP_DATETIME);
|
set_zero_time(&ends, MYSQL_TIMESTAMP_DATETIME);
|
||||||
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
|
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
|
||||||
set_zero_time(&last_executed, 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.str= definer_host.str= 0;
|
||||||
definer_user.length= definer_host.length= 0;
|
definer_user.length= definer_host.length= 0;
|
||||||
@ -115,7 +116,7 @@ event_timed::init_body(THD *thd)
|
|||||||
body_begin, thd->lex->ptr));
|
body_begin, thd->lex->ptr));
|
||||||
|
|
||||||
body.length= thd->lex->ptr - body_begin;
|
body.length= thd->lex->ptr - body_begin;
|
||||||
// Trim nuls at the end
|
/* Trim nuls at the end */
|
||||||
while (body.length && body_begin[body.length-1] == '\0')
|
while (body.length && body_begin[body.length-1] == '\0')
|
||||||
body.length--;
|
body.length--;
|
||||||
|
|
||||||
@ -158,11 +159,15 @@ event_timed::init_execute_at(THD *thd, Item *expr)
|
|||||||
if (expr->fix_fields(thd, &expr))
|
if (expr->fix_fields(thd, &expr))
|
||||||
DBUG_RETURN(EVEX_PARSE_ERROR);
|
DBUG_RETURN(EVEX_PARSE_ERROR);
|
||||||
|
|
||||||
/* Let's check whether time is in the past */
|
/* 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,
|
thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,
|
||||||
(my_time_t) thd->query_start());
|
(my_time_t) thd->query_start());
|
||||||
|
|
||||||
|
|
||||||
if ((not_used= expr->get_date(<ime, TIME_NO_ZERO_DATE)))
|
if ((not_used= expr->get_date(<ime, TIME_NO_ZERO_DATE)))
|
||||||
DBUG_RETURN(ER_WRONG_VALUE);
|
DBUG_RETURN(ER_WRONG_VALUE);
|
||||||
|
|
||||||
@ -177,7 +182,7 @@ event_timed::init_execute_at(THD *thd, Item *expr)
|
|||||||
*/
|
*/
|
||||||
my_tz_UTC->gmt_sec_to_TIME(<ime, TIME_to_timestamp(thd,<ime, ¬_used));
|
my_tz_UTC->gmt_sec_to_TIME(<ime, TIME_to_timestamp(thd,<ime, ¬_used));
|
||||||
|
|
||||||
|
execute_at_null= FALSE;
|
||||||
execute_at= ltime;
|
execute_at= ltime;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
@ -246,14 +251,14 @@ event_timed::init_interval(THD *thd, Item *expr, interval_type new_interval)
|
|||||||
case INTERVAL_DAY_MINUTE:
|
case INTERVAL_DAY_MINUTE:
|
||||||
expression= (interval.day* 24 + interval.hour) * 60 + interval.minute;
|
expression= (interval.day* 24 + interval.hour) * 60 + interval.minute;
|
||||||
break;
|
break;
|
||||||
case INTERVAL_HOUR_SECOND: // day is anyway 0
|
case INTERVAL_HOUR_SECOND: /* day is anyway 0 */
|
||||||
case INTERVAL_DAY_SECOND:
|
case INTERVAL_DAY_SECOND:
|
||||||
/* DAY_SECOND having problems because of leap seconds? */
|
/* DAY_SECOND having problems because of leap seconds? */
|
||||||
expression= ((interval.day* 24 + interval.hour) * 60 + interval.minute)*60
|
expression= ((interval.day* 24 + interval.hour) * 60 + interval.minute)*60
|
||||||
+ interval.second;
|
+ interval.second;
|
||||||
break;
|
break;
|
||||||
case INTERVAL_MINUTE_MICROSECOND: // day and hour are 0
|
case INTERVAL_MINUTE_MICROSECOND: /* day and hour are 0 */
|
||||||
case INTERVAL_HOUR_MICROSECOND:// day is anyway 0
|
case INTERVAL_HOUR_MICROSECOND: /* day is anyway 0 */
|
||||||
case INTERVAL_DAY_MICROSECOND:
|
case INTERVAL_DAY_MICROSECOND:
|
||||||
DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
|
DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
|
||||||
expression= ((((interval.day*24) + interval.hour)*60+interval.minute)*60 +
|
expression= ((((interval.day*24) + interval.hour)*60+interval.minute)*60 +
|
||||||
@ -332,6 +337,7 @@ event_timed::init_starts(THD *thd, Item *new_starts)
|
|||||||
my_tz_UTC->gmt_sec_to_TIME(<ime, TIME_to_timestamp(thd, <ime, ¬_used));
|
my_tz_UTC->gmt_sec_to_TIME(<ime, TIME_to_timestamp(thd, <ime, ¬_used));
|
||||||
|
|
||||||
starts= ltime;
|
starts= ltime;
|
||||||
|
starts_null= FALSE;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -361,8 +367,7 @@ event_timed::init_starts(THD *thd, Item *new_starts)
|
|||||||
int
|
int
|
||||||
event_timed::init_ends(THD *thd, Item *new_ends)
|
event_timed::init_ends(THD *thd, Item *new_ends)
|
||||||
{
|
{
|
||||||
TIME ltime;
|
TIME ltime, ltime_now;
|
||||||
my_time_t my_time_tmp;
|
|
||||||
my_bool not_used;
|
my_bool not_used;
|
||||||
|
|
||||||
DBUG_ENTER("event_timed::init_ends");
|
DBUG_ENTER("event_timed::init_ends");
|
||||||
@ -370,20 +375,34 @@ event_timed::init_ends(THD *thd, Item *new_ends)
|
|||||||
if (new_ends->fix_fields(thd, &new_ends))
|
if (new_ends->fix_fields(thd, &new_ends))
|
||||||
DBUG_RETURN(EVEX_PARSE_ERROR);
|
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)))
|
if ((not_used= new_ends->get_date(<ime, TIME_NO_ZERO_DATE)))
|
||||||
DBUG_RETURN(EVEX_BAD_PARAMS);
|
DBUG_RETURN(EVEX_BAD_PARAMS);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
This may result in a 1970-01-01 date if ltime is > 2037-xx-xx.
|
This may result in a 1970-01-01 date if ltime is > 2037-xx-xx ?
|
||||||
CONVERT_TZ has similar problem.
|
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));
|
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);
|
DBUG_RETURN(EVEX_BAD_PARAMS);
|
||||||
|
|
||||||
ends= ltime;
|
ends= ltime;
|
||||||
|
ends_null= FALSE;
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -515,31 +534,40 @@ event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
|
|||||||
et->definer_user.str= strmake_root(mem_root, et->definer.str, len);
|
et->definer_user.str= strmake_root(mem_root, et->definer.str, len);
|
||||||
et->definer_user.length= len;
|
et->definer_user.length= len;
|
||||||
len= et->definer.length - len - 1; //1 is because of @
|
len= et->definer.length - len - 1; //1 is because of @
|
||||||
et->definer_host.str= strmake_root(mem_root, ptr + 1, len);//1: because of @
|
et->definer_host.str= strmake_root(mem_root, ptr + 1, len);/* 1:because of @*/
|
||||||
et->definer_host.length= len;
|
et->definer_host.length= len;
|
||||||
|
|
||||||
res1= table->field[EVEX_FIELD_STARTS]->
|
et->starts_null= table->field[EVEX_FIELD_STARTS]->is_null();
|
||||||
get_date(&et->starts, TIME_NO_ZERO_DATE);
|
res1= table->field[EVEX_FIELD_STARTS]->get_date(&et->starts,TIME_NO_ZERO_DATE);
|
||||||
|
|
||||||
res2= table->field[EVEX_FIELD_ENDS]->
|
et->ends_null= table->field[EVEX_FIELD_ENDS]->is_null();
|
||||||
get_date(&et->ends, TIME_NO_ZERO_DATE);
|
res2= table->field[EVEX_FIELD_ENDS]->get_date(&et->ends, TIME_NO_ZERO_DATE);
|
||||||
|
|
||||||
|
if (!table->field[EVEX_FIELD_INTERVAL_EXPR]->is_null())
|
||||||
et->expression= table->field[EVEX_FIELD_INTERVAL_EXPR]->val_int();
|
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.
|
If res1 and res2 are true then both fields are empty.
|
||||||
Hence if EVEX_FIELD_EXECUTE_AT is empty there is an error.
|
Hence if EVEX_FIELD_EXECUTE_AT is empty there is an error.
|
||||||
*/
|
*/
|
||||||
if (res1 && res2 && !et->expression && table->field[EVEX_FIELD_EXECUTE_AT]->
|
et->execute_at_null= table->field[EVEX_FIELD_EXECUTE_AT]->is_null();
|
||||||
get_date(&et->execute_at, TIME_NO_ZERO_DATE))
|
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;
|
goto error;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
In DB the values start from 1 but enum interval_type starts
|
In DB the values start from 1 but enum interval_type starts
|
||||||
from 0
|
from 0
|
||||||
*/
|
*/
|
||||||
|
if (!table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->is_null())
|
||||||
et->interval= (interval_type)
|
et->interval= (interval_type)
|
||||||
((ulonglong) table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->val_int() - 1);
|
((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->modified= table->field[EVEX_FIELD_CREATED]->val_int();
|
||||||
et->created= table->field[EVEX_FIELD_MODIFIED]->val_int();
|
et->created= table->field[EVEX_FIELD_MODIFIED]->val_int();
|
||||||
@ -568,14 +596,14 @@ event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
|
|||||||
#endif
|
#endif
|
||||||
last_executed_changed= false;
|
last_executed_changed= false;
|
||||||
|
|
||||||
// ToDo : Andrey . Find a way not to allocate ptr on event_mem_root
|
/* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
|
||||||
if ((ptr= get_field(mem_root, table->field[EVEX_FIELD_STATUS])) == NullS)
|
if ((ptr= get_field(mem_root, table->field[EVEX_FIELD_STATUS])) == NullS)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", et->name.str, ptr));
|
DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", et->name.str, ptr));
|
||||||
et->status= (ptr[0]=='E'? MYSQL_EVENT_ENABLED:MYSQL_EVENT_DISABLED);
|
et->status= (ptr[0]=='E'? MYSQL_EVENT_ENABLED:MYSQL_EVENT_DISABLED);
|
||||||
|
|
||||||
// ToDo : Andrey . Find a way not to allocate ptr on event_mem_root
|
/* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
|
||||||
if ((ptr= get_field(mem_root,
|
if ((ptr= get_field(mem_root,
|
||||||
table->field[EVEX_FIELD_ON_COMPLETION])) == NullS)
|
table->field[EVEX_FIELD_ON_COMPLETION])) == NullS)
|
||||||
goto error;
|
goto error;
|
||||||
@ -698,14 +726,11 @@ event_timed::compute_next_execution_time()
|
|||||||
/* Let's check whether it was executed */
|
/* Let's check whether it was executed */
|
||||||
if (last_executed.year)
|
if (last_executed.year)
|
||||||
{
|
{
|
||||||
DBUG_PRINT("compute_next_execution_time",
|
DBUG_PRINT("info",("One-time event %s.%s of was already executed",
|
||||||
("One-time event %s was already executed", name.str));
|
dbname.str, name.str, definer.str));
|
||||||
if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
|
dropped= (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP);
|
||||||
{
|
DBUG_PRINT("info",("One-time event will be dropped=%d.", dropped));
|
||||||
DBUG_PRINT("compute_next_execution_time",
|
|
||||||
("One-time event will be dropped."));
|
|
||||||
dropped= true;
|
|
||||||
}
|
|
||||||
status= MYSQL_EVENT_DISABLED;
|
status= MYSQL_EVENT_DISABLED;
|
||||||
status_changed= true;
|
status_changed= true;
|
||||||
}
|
}
|
||||||
@ -731,11 +756,12 @@ event_timed::compute_next_execution_time()
|
|||||||
last_executed.second);
|
last_executed.second);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If time_now is after ends don't execute anymore */
|
/* 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 */
|
/* time_now is after ends. don't execute anymore */
|
||||||
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
|
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
|
||||||
|
execute_at_null= TRUE;
|
||||||
if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
|
if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
|
||||||
dropped= true;
|
dropped= true;
|
||||||
status= MYSQL_EVENT_DISABLED;
|
status= MYSQL_EVENT_DISABLED;
|
||||||
@ -749,7 +775,7 @@ event_timed::compute_next_execution_time()
|
|||||||
Let's check whether time_now is before starts.
|
Let's check whether time_now is before starts.
|
||||||
If so schedule for 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)
|
if (tmp == 0 && my_time_compare(&starts, &last_executed) == 0)
|
||||||
{
|
{
|
||||||
@ -765,11 +791,12 @@ event_timed::compute_next_execution_time()
|
|||||||
time_now before starts. Scheduling for starts
|
time_now before starts. Scheduling for starts
|
||||||
*/
|
*/
|
||||||
execute_at= starts;
|
execute_at= starts;
|
||||||
|
execute_at_null= FALSE;
|
||||||
goto ret;
|
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.)
|
Both starts and m_ends are set and time_now is between them (incl.)
|
||||||
@ -778,7 +805,10 @@ event_timed::compute_next_execution_time()
|
|||||||
If not set then schedule for now.
|
If not set then schedule for now.
|
||||||
*/
|
*/
|
||||||
if (!last_executed.year)
|
if (!last_executed.year)
|
||||||
|
{
|
||||||
execute_at= time_now;
|
execute_at= time_now;
|
||||||
|
execute_at_null= FALSE;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
TIME next_exec;
|
TIME next_exec;
|
||||||
@ -791,15 +821,19 @@ event_timed::compute_next_execution_time()
|
|||||||
{
|
{
|
||||||
/* Next execution after ends. No more executions */
|
/* Next execution after ends. No more executions */
|
||||||
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
|
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
|
||||||
|
execute_at_null= TRUE;
|
||||||
if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
|
if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
|
||||||
dropped= true;
|
dropped= true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
execute_at= next_exec;
|
execute_at= next_exec;
|
||||||
|
execute_at_null= FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
goto ret;
|
goto ret;
|
||||||
}
|
}
|
||||||
else if (!starts.year && !ends.year)
|
else if (starts_null && ends_null)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
Both starts and m_ends are not set, so we schedule for the next
|
Both starts and m_ends are not set, so we schedule for the next
|
||||||
@ -815,11 +849,12 @@ event_timed::compute_next_execution_time()
|
|||||||
/* last_executed not set. Schedule the event for now */
|
/* last_executed not set. Schedule the event for now */
|
||||||
execute_at= time_now;
|
execute_at= time_now;
|
||||||
}
|
}
|
||||||
|
execute_at_null= FALSE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Either starts or m_ends is set */
|
/* either starts or m_ends is set */
|
||||||
if (starts.year)
|
if (!starts_null)
|
||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
- starts is set.
|
- starts is set.
|
||||||
@ -834,6 +869,7 @@ event_timed::compute_next_execution_time()
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
execute_at= starts;
|
execute_at= starts;
|
||||||
|
execute_at_null= FALSE;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -856,11 +892,15 @@ event_timed::compute_next_execution_time()
|
|||||||
if (my_time_compare(&ends, &next_exec) == -1)
|
if (my_time_compare(&ends, &next_exec) == -1)
|
||||||
{
|
{
|
||||||
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
|
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
|
||||||
|
execute_at_null= TRUE;
|
||||||
if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
|
if (on_completion == MYSQL_EVENT_ON_COMPLETION_DROP)
|
||||||
dropped= true;
|
dropped= true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
{
|
||||||
execute_at= next_exec;
|
execute_at= next_exec;
|
||||||
|
execute_at_null= FALSE;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
goto ret;
|
goto ret;
|
||||||
@ -890,7 +930,7 @@ event_timed::mark_last_executed(THD *thd)
|
|||||||
thd->end_time();
|
thd->end_time();
|
||||||
my_tz_UTC->gmt_sec_to_TIME(&time_now, (my_time_t) thd->query_start());
|
my_tz_UTC->gmt_sec_to_TIME(&time_now, (my_time_t) thd->query_start());
|
||||||
|
|
||||||
last_executed= time_now; // was execute_at
|
last_executed= time_now; /* was execute_at */
|
||||||
#ifdef ANDREY_0
|
#ifdef ANDREY_0
|
||||||
last_executed= execute_at;
|
last_executed= execute_at;
|
||||||
#endif
|
#endif
|
||||||
@ -1045,7 +1085,7 @@ event_timed::get_create_event(THD *thd, String *buf)
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
char dtime_buff[20*2+32];// +32 to make my_snprintf_{8bit|ucs2} happy
|
char dtime_buff[20*2+32];/* +32 to make my_snprintf_{8bit|ucs2} happy */
|
||||||
buf->append(STRING_WITH_LEN("AT '"));
|
buf->append(STRING_WITH_LEN("AT '"));
|
||||||
/*
|
/*
|
||||||
Pass the buffer and the second param tells fills the buffer and
|
Pass the buffer and the second param tells fills the buffer and
|
||||||
@ -1324,10 +1364,7 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root)
|
|||||||
|
|
||||||
sphead= lex.et->sphead;
|
sphead= lex.et->sphead;
|
||||||
sphead->m_db= dbname;
|
sphead->m_db= dbname;
|
||||||
/*
|
|
||||||
Ccopy also chistics since they will vanish otherwise we get 0x0 pointer
|
|
||||||
TODO: Handle sql_mode!!
|
|
||||||
*/
|
|
||||||
sphead->set_definer(definer.str, definer.length);
|
sphead->set_definer(definer.str, definer.length);
|
||||||
sphead->set_info(0, 0, &lex.sp_chistics, sql_mode);
|
sphead->set_info(0, 0, &lex.sp_chistics, sql_mode);
|
||||||
sphead->optimize();
|
sphead->optimize();
|
||||||
@ -1460,7 +1497,6 @@ event_timed::spawn_thread_finish(THD *thd)
|
|||||||
Returns
|
Returns
|
||||||
0 - ok
|
0 - ok
|
||||||
1 - not locked by this thread
|
1 - not locked by this thread
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
@ -3957,7 +3957,7 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
|
|||||||
sch_table->field[3]->store(et.definer.str, et.definer.length, scs);
|
sch_table->field[3]->store(et.definer.str, et.definer.length, scs);
|
||||||
sch_table->field[4]->store(et.body.str, et.body.length, scs);
|
sch_table->field[4]->store(et.body.str, et.body.length, scs);
|
||||||
|
|
||||||
// [9] is SQL_MODE
|
/* [9] is SQL_MODE */
|
||||||
{
|
{
|
||||||
byte *sql_mode_str;
|
byte *sql_mode_str;
|
||||||
ulong sql_mode_len=0;
|
ulong sql_mode_len=0;
|
||||||
@ -3972,9 +3972,9 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
|
|||||||
String show_str;
|
String show_str;
|
||||||
//type
|
//type
|
||||||
sch_table->field[5]->store(STRING_WITH_LEN("RECURRING"), scs);
|
sch_table->field[5]->store(STRING_WITH_LEN("RECURRING"), scs);
|
||||||
//execute_at
|
/* execute_at */
|
||||||
sch_table->field[6]->set_null();
|
sch_table->field[6]->set_null();
|
||||||
//interval_value
|
/* interval_value */
|
||||||
//interval_type
|
//interval_type
|
||||||
if (event_reconstruct_interval_expression(&show_str, et.interval,
|
if (event_reconstruct_interval_expression(&show_str, et.interval,
|
||||||
et.expression))
|
et.expression))
|
||||||
@ -3986,26 +3986,24 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
|
|||||||
LEX_STRING *ival= &interval_type_to_name[et.interval];
|
LEX_STRING *ival= &interval_type_to_name[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);
|
||||||
|
|
||||||
|
if (!et.ends_null)
|
||||||
|
{
|
||||||
sch_table->field[11]->set_notnull();
|
sch_table->field[11]->set_notnull();
|
||||||
sch_table->field[11]->store_time(&et.ends, MYSQL_TIMESTAMP_DATETIME);
|
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
|
||||||
|
@ -1476,6 +1476,9 @@ opt_ev_status: /* empty */ { $$= 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;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user