2
Copyright (c) 2005, 2011, Oracle and/or its affiliates.
4
This program is free software; you can redistribute it and/or modify
5
it under the terms of the GNU General Public License as published by
6
the Free Software Foundation; version 2 of the License.
8
This program is distributed in the hope that it will be useful,
9
but WITHOUT ANY WARRANTY; without even the implied warranty of
10
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11
GNU General Public License for more details.
13
You should have received a copy of the GNU General Public License
14
along with this program; if not, write to the Free Software
15
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
19
#include "sql_parse.h" // check_access
20
#include "sql_base.h" // close_mysql_tables
21
#include "sql_show.h" // append_definer
23
#include "sql_db.h" // check_db_dir_existence
24
#include "sql_table.h" // write_bin_log
25
#include "tztime.h" // struct Time_zone
26
#include "sql_acl.h" // EVENT_ACL
27
#include "records.h" // init_read_record, end_read_record
28
#include "event_data_objects.h"
29
#include "event_db_repository.h"
30
#include "event_queue.h"
31
#include "event_scheduler.h"
32
#include "sp_head.h" // for Stored_program_creation_ctx
34
#include "lock.h" // lock_object_name
37
@addtogroup Event_Scheduler
43
- CREATE EVENT should not go into binary log! Does it now? The SQL statements
44
issued by the EVENT are replicated.
45
I have an idea how to solve the problem at failover. So the status field
46
will be ENUM('DISABLED', 'ENABLED', 'SLAVESIDE_DISABLED').
47
In this case when CREATE EVENT is replicated it should go into the binary
48
as SLAVESIDE_DISABLED if it is ENABLED, when it's created as DISABLEd it
49
should be replicated as disabled. If an event is ALTERed as DISABLED the
50
query should go untouched into the binary log, when ALTERed as enable then
51
it should go as SLAVESIDE_DISABLED. This is regarding the SQL interface.
52
TT routines however modify mysql.event internally and this does not go the
53
log so in this case queries has to be injected into the log...somehow... or
54
maybe a solution is RBR for this case, because the event may go only from
55
ENABLED to DISABLED status change and this is safe for replicating. As well
56
an event may be deleted which is also safe for RBR.
64
If the user (un)intentionally removes an event directly from mysql.event
65
the following sequence has to be used to be able to remove the in-memory
67
1. CREATE EVENT the_name ON SCHEDULE EVERY 1 SECOND DISABLE DO SELECT 1;
68
2. DROP EVENT the_name
70
In other words, the first one will create a row in mysql.event . In the
71
second step because there will be a line, disk based drop will pass and
72
the scheduler will remove the memory counterpart. The reason is that
73
in-memory queue does not check whether the event we try to drop from memory
74
is disabled. Disabled events are not kept in-memory because they are not
75
eligible for execution.
78
Event_queue *Events::event_queue;
79
Event_scheduler *Events::scheduler;
80
Event_db_repository *Events::db_repository;
81
ulong Events::opt_event_scheduler= Events::EVENTS_OFF;
82
bool Events::check_system_tables_error= FALSE;
86
Compares 2 LEX strings regarding case.
100
int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
102
return cs->coll->strnncollsp(cs, (uchar *) s.str,s.length,
103
(uchar *) t.str,t.length, 0);
108
Push an error into the error stack if the system tables are
112
bool Events::check_if_system_tables_error()
114
DBUG_ENTER("Events::check_if_system_tables_error");
116
if (check_system_tables_error)
118
my_error(ER_EVENTS_DB_ERROR, MYF(0));
127
Reconstructs interval expression from interval type and expression
128
value that is in form of a value of the smalles entity:
130
YEAR_MONTH - expression is in months
131
DAY_MINUTE - expression is in minutes
134
Events::reconstruct_interval_expression()
135
buf Preallocated String buffer to add the value to
136
interval The interval type (for instance YEAR_MONTH)
137
expression The value in the lowest entity
145
Events::reconstruct_interval_expression(String *buf, interval_type interval,
148
ulonglong expr= expression;
149
char tmp_buff[128], *end;
150
bool close_quote= TRUE;
155
case INTERVAL_YEAR_MONTH:
158
goto common_1_lev_code;
159
case INTERVAL_DAY_HOUR:
162
goto common_1_lev_code;
163
case INTERVAL_HOUR_MINUTE:
164
case INTERVAL_MINUTE_SECOND:
168
end= longlong10_to_str(expression/multipl, tmp_buff, 10);
169
buf->append(tmp_buff, (uint) (end- tmp_buff));
170
expr= expr - (expr/multipl)*multipl;
172
case INTERVAL_DAY_MINUTE:
174
ulonglong tmp_expr= expr;
178
end= longlong10_to_str(tmp_expr, tmp_buff, 10);
179
buf->append(tmp_buff, (uint) (end- tmp_buff));// days
182
tmp_expr= expr - tmp_expr*(24*60);//minutes left
183
end= longlong10_to_str(tmp_expr/60, tmp_buff, 10);
184
buf->append(tmp_buff, (uint) (end- tmp_buff));// hours
186
expr= tmp_expr - (tmp_expr/60)*60;
187
/* the code after the switch will finish */
190
case INTERVAL_HOUR_SECOND:
192
ulonglong tmp_expr= expr;
195
end= longlong10_to_str(tmp_expr/3600, tmp_buff, 10);
196
buf->append(tmp_buff, (uint) (end- tmp_buff));// hours
199
tmp_expr= tmp_expr - (tmp_expr/3600)*3600;
200
end= longlong10_to_str(tmp_expr/60, tmp_buff, 10);
201
buf->append(tmp_buff, (uint) (end- tmp_buff));// minutes
203
expr= tmp_expr - (tmp_expr/60)*60;
204
/* the code after the switch will finish */
207
case INTERVAL_DAY_SECOND:
209
ulonglong tmp_expr= expr;
213
end= longlong10_to_str(tmp_expr, tmp_buff, 10);
214
buf->append(tmp_buff, (uint) (end- tmp_buff));// days
217
tmp_expr= expr - tmp_expr*(24*3600);//seconds left
218
end= longlong10_to_str(tmp_expr/3600, tmp_buff, 10);
219
buf->append(tmp_buff, (uint) (end- tmp_buff));// hours
222
tmp_expr= tmp_expr - (tmp_expr/3600)*3600;
223
end= longlong10_to_str(tmp_expr/60, tmp_buff, 10);
224
buf->append(tmp_buff, (uint) (end- tmp_buff));// minutes
226
expr= tmp_expr - (tmp_expr/60)*60;
227
/* the code after the switch will finish */
230
case INTERVAL_DAY_MICROSECOND:
231
case INTERVAL_HOUR_MICROSECOND:
232
case INTERVAL_MINUTE_MICROSECOND:
233
case INTERVAL_SECOND_MICROSECOND:
234
case INTERVAL_MICROSECOND:
235
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND");
237
case INTERVAL_QUARTER:
248
buf->append(separator);
249
end= longlong10_to_str(expr, tmp_buff, 10);
250
buf->append(tmp_buff, (uint) (end- tmp_buff));
259
Create a new query string for removing executable comments
260
for avoiding leak and keeping consistency of the execution
263
@param[in] thd Thread handler
264
@param[in] buf Query string
271
create_query_string(THD *thd, String *buf)
273
/* Append the "CREATE" part of the query */
274
if (buf->append(STRING_WITH_LEN("CREATE ")))
277
append_definer(thd, buf, &(thd->lex->definer->user), &(thd->lex->definer->host));
278
/* Append the left part of thd->query after "DEFINER" part */
279
if (buf->append(thd->lex->stmt_definition_begin,
280
thd->lex->stmt_definition_end -
281
thd->lex->stmt_definition_begin))
291
@param[in,out] thd THD
292
@param[in] parse_data Event's data from parsing stage
293
@param[in] if_not_exists Whether IF NOT EXISTS was
295
In case there is an event with the same name (db) and
296
IF NOT EXISTS is specified, an warning is put into the stack.
297
@sa Events::drop_event for the notes about locking, pre-locking
301
@retval TRUE Error (reported)
305
Events::create_event(THD *thd, Event_parse_data *parse_data,
309
bool save_binlog_row_based, event_already_exists;
310
DBUG_ENTER("Events::create_event");
312
if (check_if_system_tables_error())
316
Perform semantic checks outside of Event_db_repository:
317
once CREATE EVENT is supported in prepared statements, the
318
checks will be moved to PREPARE phase.
320
if (parse_data->check_parse_data(thd))
323
/* At create, one of them must be set */
324
DBUG_ASSERT(parse_data->expression || parse_data->execute_at);
326
if (check_access(thd, EVENT_ACL, parse_data->dbname.str, NULL, NULL, 0, 0))
329
if (check_db_dir_existence(parse_data->dbname.str))
331
my_error(ER_BAD_DB_ERROR, MYF(0), parse_data->dbname.str);
335
if (parse_data->do_not_create)
338
Turn off row binlogging of this statement and use statement-based
339
so that all supporting tables are updated for CREATE EVENT command.
341
if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
342
thd->clear_current_stmt_binlog_format_row();
344
if (lock_object_name(thd, MDL_key::EVENT,
345
parse_data->dbname.str, parse_data->name.str))
348
/* On error conditions my_error() is called so no need to handle here */
349
if (!(ret= db_repository->create_event(thd, parse_data, if_not_exists,
350
&event_already_exists)))
352
Event_queue_element *new_element;
355
if (!event_already_exists)
357
if (!(new_element= new Event_queue_element()))
359
else if ((ret= db_repository->load_named_event(thd, parse_data->dbname,
363
if (!db_repository->drop_event(thd, parse_data->dbname,
364
parse_data->name, TRUE))
370
/* TODO: do not ignore the out parameter and a possible OOM error! */
373
event_queue->create_event(thd, new_element, &created);
377
binlog the create event unless it's been successfully dropped
381
/* Binlog the create event. */
382
DBUG_ASSERT(thd->query() && thd->query_length());
384
if (create_query_string(thd, &log_query))
386
sql_print_error("Event Error: An error occurred while creating query "
387
"string, before writing it into binary log.");
393
If the definer is not set or set to CURRENT_USER, the value
394
of CURRENT_USER will be written into the binary log as the
395
definer for the SQL thread.
397
ret= write_bin_log(thd, TRUE, log_query.ptr(), log_query.length());
401
/* Restore the state of binlog format */
402
DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
403
if (save_binlog_row_based)
404
thd->set_current_stmt_binlog_format_row();
413
@param[in,out] thd THD
414
@param[in] parse_data Event's data from parsing stage
415
@param[in] new_dbname A new schema name for the event. Set in the case of
416
ALTER EVENT RENAME, otherwise is NULL.
417
@param[in] new_name A new name for the event. Set in the case of
420
Parameter 'et' contains data about dbname and event name.
421
Parameter 'new_name' is the new name of the event, if not null
422
this means that RENAME TO was specified in the query
423
@sa Events::drop_event for the locking notes.
426
@retval TRUE error (reported)
430
Events::update_event(THD *thd, Event_parse_data *parse_data,
431
LEX_STRING *new_dbname, LEX_STRING *new_name)
434
bool save_binlog_row_based;
435
Event_queue_element *new_element;
437
DBUG_ENTER("Events::update_event");
439
if (check_if_system_tables_error())
442
if (parse_data->check_parse_data(thd) || parse_data->do_not_create)
445
if (check_access(thd, EVENT_ACL, parse_data->dbname.str, NULL, NULL, 0, 0))
448
if (new_dbname) /* It's a rename */
450
/* Check that the new and the old names differ. */
451
if ( !sortcmp_lex_string(parse_data->dbname, *new_dbname,
452
system_charset_info) &&
453
!sortcmp_lex_string(parse_data->name, *new_name,
454
system_charset_info))
456
my_error(ER_EVENT_SAME_NAME, MYF(0));
461
And the user has sufficient privileges to use the target database.
462
Do it before checking whether the database exists: we don't want
463
to tell the user that a database doesn't exist if they can not
466
if (check_access(thd, EVENT_ACL, new_dbname->str, NULL, NULL, 0, 0))
469
/* Check that the target database exists */
470
if (check_db_dir_existence(new_dbname->str))
472
my_error(ER_BAD_DB_ERROR, MYF(0), new_dbname->str);
478
Turn off row binlogging of this statement and use statement-based
479
so that all supporting tables are updated for UPDATE EVENT command.
481
if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
482
thd->clear_current_stmt_binlog_format_row();
484
if (lock_object_name(thd, MDL_key::EVENT,
485
parse_data->dbname.str, parse_data->name.str))
488
/* On error conditions my_error() is called so no need to handle here */
489
if (!(ret= db_repository->update_event(thd, parse_data,
490
new_dbname, new_name)))
492
LEX_STRING dbname= new_dbname ? *new_dbname : parse_data->dbname;
493
LEX_STRING name= new_name ? *new_name : parse_data->name;
495
if (!(new_element= new Event_queue_element()))
497
else if ((ret= db_repository->load_named_event(thd, dbname, name,
503
TODO: check if an update actually has inserted an entry
505
If not, and the element is ON COMPLETION NOT PRESERVE, delete
509
event_queue->update_event(thd, parse_data->dbname, parse_data->name,
511
/* Binlog the alter event. */
512
DBUG_ASSERT(thd->query() && thd->query_length());
513
ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
516
/* Restore the state of binlog format */
517
DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
518
if (save_binlog_row_based)
519
thd->set_current_stmt_binlog_format_row();
528
@param[in,out] thd THD
529
@param[in] dbname Event's schema
530
@param[in] name Event's name
531
@param[in] if_exists When this is set and the event does not exist
532
a warning is pushed into the warning stack.
533
Otherwise the operation produces an error.
535
@note Similarly to DROP PROCEDURE, we do not allow DROP EVENT
536
under LOCK TABLES mode, unless table mysql.event is locked. To
537
ensure that, we do not reset & backup the open tables state in
538
this function - if in LOCK TABLES or pre-locking mode, this will
539
lead to an error 'Table mysql.event is not locked with LOCK
540
TABLES' unless it _is_ locked. In pre-locked mode there is
541
another barrier - DROP EVENT commits the current transaction,
542
and COMMIT/ROLLBACK is not allowed in stored functions and
546
@retval TRUE Error (reported)
550
Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists)
553
bool save_binlog_row_based;
554
DBUG_ENTER("Events::drop_event");
556
if (check_if_system_tables_error())
559
if (check_access(thd, EVENT_ACL, dbname.str, NULL, NULL, 0, 0))
563
Turn off row binlogging of this statement and use statement-based so
564
that all supporting tables are updated for DROP EVENT command.
566
if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
567
thd->clear_current_stmt_binlog_format_row();
569
if (lock_object_name(thd, MDL_key::EVENT,
570
dbname.str, name.str))
572
/* On error conditions my_error() is called so no need to handle here */
573
if (!(ret= db_repository->drop_event(thd, dbname, name, if_exists)))
576
event_queue->drop_event(thd, dbname, name);
577
/* Binlog the drop event. */
578
DBUG_ASSERT(thd->query() && thd->query_length());
579
ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
581
/* Restore the state of binlog format */
582
DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
583
if (save_binlog_row_based)
584
thd->set_current_stmt_binlog_format_row();
590
Drops all events from a schema
592
@note We allow to drop all events in a schema even if the
593
scheduler is disabled. This is to not produce any warnings
594
in case of DROP DATABASE and a disabled scheduler.
596
@param[in,out] thd Thread
597
@param[in] db ASCIIZ schema name
601
Events::drop_schema_events(THD *thd, char *db)
603
LEX_STRING const db_lex= { db, strlen(db) };
605
DBUG_ENTER("Events::drop_schema_events");
606
DBUG_PRINT("enter", ("dropping events from %s", db));
609
Sic: no check if the scheduler is disabled or system tables
610
are damaged, as intended.
613
event_queue->drop_schema_events(thd, db_lex);
614
db_repository->drop_schema_events(thd, db_lex);
621
A helper function to generate SHOW CREATE EVENT output from
626
send_show_create_event(THD *thd, Event_timed *et, Protocol *protocol)
628
char show_str_buf[10 * STRING_BUFFER_USUAL_SIZE];
629
String show_str(show_str_buf, sizeof(show_str_buf), system_charset_info);
630
List<Item> field_list;
632
const String *tz_name;
634
DBUG_ENTER("send_show_create_event");
637
if (et->get_create_event(thd, &show_str))
640
field_list.push_back(new Item_empty_string("Event", NAME_CHAR_LEN));
642
if (sql_mode_string_representation(thd, et->sql_mode, &sql_mode))
645
field_list.push_back(new Item_empty_string("sql_mode", (uint) sql_mode.length));
647
tz_name= et->time_zone->get_name();
649
field_list.push_back(new Item_empty_string("time_zone",
652
field_list.push_back(new Item_empty_string("Create Event",
655
field_list.push_back(
656
new Item_empty_string("character_set_client", MY_CS_NAME_SIZE));
658
field_list.push_back(
659
new Item_empty_string("collation_connection", MY_CS_NAME_SIZE));
661
field_list.push_back(
662
new Item_empty_string("Database Collation", MY_CS_NAME_SIZE));
664
if (protocol->send_result_set_metadata(&field_list,
665
Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
668
protocol->prepare_for_resend();
670
protocol->store(et->name.str, et->name.length, system_charset_info);
671
protocol->store(sql_mode.str, sql_mode.length, system_charset_info);
672
protocol->store(tz_name->ptr(), tz_name->length(), system_charset_info);
673
protocol->store(show_str.ptr(), show_str.length(),
674
et->creation_ctx->get_client_cs());
675
protocol->store(et->creation_ctx->get_client_cs()->csname,
676
strlen(et->creation_ctx->get_client_cs()->csname),
677
system_charset_info);
678
protocol->store(et->creation_ctx->get_connection_cl()->name,
679
strlen(et->creation_ctx->get_connection_cl()->name),
680
system_charset_info);
681
protocol->store(et->creation_ctx->get_db_cl()->name,
682
strlen(et->creation_ctx->get_db_cl()->name),
683
system_charset_info);
685
if (protocol->write())
695
Implement SHOW CREATE EVENT statement
698
spn The name of the event (db, name)
701
@retval TRUE error (reported)
705
Events::show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
710
DBUG_ENTER("Events::show_create_event");
711
DBUG_PRINT("enter", ("name: %s@%s", dbname.str, name.str));
713
if (check_if_system_tables_error())
716
if (check_access(thd, EVENT_ACL, dbname.str, NULL, NULL, 0, 0))
720
We would like to allow SHOW CREATE EVENT under LOCK TABLES and
721
in pre-locked mode. mysql.event table is marked as a system table.
722
This flag reduces the set of its participation scenarios in LOCK TABLES
723
operation, and therefore an out-of-bound open of this table
724
for reading like the one below (sic, only for reading) is
725
more or less deadlock-free. For additional information about when a
726
deadlock can occur please refer to the description of 'system table'
729
ret= db_repository->load_named_event(thd, dbname, name, &et);
732
ret= send_show_create_event(thd, &et, thd->protocol);
739
Check access rights and fill INFORMATION_SCHEMA.events table.
741
@param[in,out] thd Thread context
742
@param[in] tables The temporary table to fill.
744
In MySQL INFORMATION_SCHEMA tables are temporary tables that are
745
created and filled on demand. In this function, we fill
746
INFORMATION_SCHEMA.events. It is a callback for I_S module, invoked from
749
@return Has to be integer, as such is the requirement of the I_S API
751
@retval 1 an error, pushed into the error stack
755
Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
759
DBUG_ENTER("Events::fill_schema_events");
761
if (check_if_system_tables_error())
765
If it's SHOW EVENTS then thd->lex->select_lex.db is guaranteed not to
766
be NULL. Let's do an assert anyway.
768
if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS)
770
DBUG_ASSERT(thd->lex->select_lex.db);
771
if (!is_infoschema_db(thd->lex->select_lex.db) && // There is no events in I_S
772
check_access(thd, EVENT_ACL, thd->lex->select_lex.db,
775
db= thd->lex->select_lex.db;
777
ret= db_repository->fill_schema_events(thd, tables, db);
784
Initializes the scheduler's structures.
786
@param opt_noacl_or_bootstrap
787
TRUE if there is --skip-grant-tables or --bootstrap
788
option. In that case we disable the event scheduler.
790
@note This function is not synchronized.
792
@retval FALSE Perhaps there was an error, and the event scheduler
793
is disabled. But the error is not fatal and the
794
server start up can continue.
795
@retval TRUE Fatal error. Startup must terminate (call unireg_abort()).
799
Events::init(bool opt_noacl_or_bootstrap)
805
DBUG_ENTER("Events::init");
807
/* We need a temporary THD during boot */
808
if (!(thd= new THD()))
814
The thread stack does not start from this function but we cannot
815
guess the real value. So better some value that doesn't assert than
818
thd->thread_stack= (char*) &thd;
819
thd->store_globals();
822
We will need Event_db_repository anyway, even if the scheduler is
823
disabled - to perform events DDL.
825
if (!(db_repository= new Event_db_repository))
827
res= TRUE; /* fatal error: request unireg_abort */
832
Since we allow event DDL even if the scheduler is disabled,
833
check the system tables, as we might need them.
835
If run with --skip-grant-tables or --bootstrap, don't try to do the
836
check of system tables and don't complain: in these modes the tables
837
are most likely not there and we're going to disable the event
840
if (opt_noacl_or_bootstrap || Event_db_repository::check_system_tables(thd))
842
if (! opt_noacl_or_bootstrap)
844
sql_print_error("Event Scheduler: An error occurred when initializing "
845
"system tables. Disabling the Event Scheduler.");
846
check_system_tables_error= TRUE;
849
/* Disable the scheduler since the system tables are not up to date */
850
opt_event_scheduler= EVENTS_DISABLED;
855
Was disabled explicitly from the command line, or because we're running
856
with --skip-grant-tables, or --bootstrap, or because we have no system
859
if (opt_event_scheduler == Events::EVENTS_DISABLED)
863
DBUG_ASSERT(opt_event_scheduler == Events::EVENTS_ON ||
864
opt_event_scheduler == Events::EVENTS_OFF);
866
if (!(event_queue= new Event_queue) ||
867
!(scheduler= new Event_scheduler(event_queue)))
869
res= TRUE; /* fatal error: request unireg_abort */
873
if (event_queue->init_queue(thd) || load_events_from_db(thd) ||
874
(opt_event_scheduler == EVENTS_ON && scheduler->start()))
876
sql_print_error("Event Scheduler: Error while loading from disk.");
877
res= TRUE; /* fatal error: request unireg_abort */
880
Event_worker_thread::init(db_repository);
885
delete db_repository;
890
/* Remember that we don't have a THD */
891
my_pthread_setspecific_ptr(THR_THD, NULL);
897
Cleans up scheduler's resources. Called at server shutdown.
903
This function is not synchronized.
909
DBUG_ENTER("Events::deinit");
911
if (opt_event_scheduler != EVENTS_DISABLED)
914
scheduler= NULL; /* safety */
916
event_queue= NULL; /* safety */
919
delete db_repository;
920
db_repository= NULL; /* safety */
925
#ifdef HAVE_PSI_INTERFACE
926
PSI_mutex_key key_LOCK_event_queue,
927
key_event_scheduler_LOCK_scheduler_state;
929
static PSI_mutex_info all_events_mutexes[]=
931
{ &key_LOCK_event_queue, "LOCK_event_queue", PSI_FLAG_GLOBAL},
932
{ &key_event_scheduler_LOCK_scheduler_state, "Event_scheduler::LOCK_scheduler_state", PSI_FLAG_GLOBAL}
935
PSI_cond_key key_event_scheduler_COND_state, key_COND_queue_state;
937
static PSI_cond_info all_events_conds[]=
939
{ &key_event_scheduler_COND_state, "Event_scheduler::COND_state", PSI_FLAG_GLOBAL},
940
{ &key_COND_queue_state, "COND_queue_state", PSI_FLAG_GLOBAL},
943
PSI_thread_key key_thread_event_scheduler, key_thread_event_worker;
945
static PSI_thread_info all_events_threads[]=
947
{ &key_thread_event_scheduler, "event_scheduler", PSI_FLAG_GLOBAL},
948
{ &key_thread_event_worker, "event_worker", 0}
951
static void init_events_psi_keys(void)
953
const char* category= "sql";
956
if (PSI_server == NULL)
959
count= array_elements(all_events_mutexes);
960
PSI_server->register_mutex(category, all_events_mutexes, count);
962
count= array_elements(all_events_conds);
963
PSI_server->register_cond(category, all_events_conds, count);
965
count= array_elements(all_events_threads);
966
PSI_server->register_thread(category, all_events_threads, count);
968
#endif /* HAVE_PSI_INTERFACE */
974
Events::init_mutexes()
979
Events::init_mutexes()
981
#ifdef HAVE_PSI_INTERFACE
982
init_events_psi_keys();
988
Dumps the internal status of the scheduler and the memory cache
989
into a table with two columns - Name & Value. Different properties
990
which could be useful for debugging for instance deadlocks are
994
Events::dump_internal_status()
998
Events::dump_internal_status()
1000
DBUG_ENTER("Events::dump_internal_status");
1001
puts("\n\n\nEvents status:");
1002
puts("LLA = Last Locked At LUA = Last Unlocked At");
1003
puts("WOC = Waiting On Condition DL = Data Locked");
1006
opt_event_scheduler should only be accessed while
1007
holding LOCK_global_system_variables.
1009
mysql_mutex_lock(&LOCK_global_system_variables);
1010
if (opt_event_scheduler == EVENTS_DISABLED)
1011
puts("The Event Scheduler is disabled");
1014
scheduler->dump_internal_status();
1015
event_queue->dump_internal_status();
1018
mysql_mutex_unlock(&LOCK_global_system_variables);
1022
bool Events::start()
1024
return scheduler->start();
1029
return scheduler->stop();
1033
Loads all ENABLED events from mysql.event into a prioritized
1036
This function is called during the server start up. It reads
1037
every event, computes the next execution time, and if the event
1038
needs execution, adds it to a prioritized queue. Otherwise, if
1039
ON COMPLETION DROP is specified, the event is automatically
1040
removed from the table.
1042
@param[in,out] thd Thread context. Used for memory allocation in some cases.
1044
@retval FALSE success
1045
@retval TRUE error, the load is aborted
1047
@note Reports the error to the console
1051
Events::load_events_from_db(THD *thd)
1054
READ_RECORD read_record_info;
1057
ulong saved_master_access;
1059
DBUG_ENTER("Events::load_events_from_db");
1060
DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
1063
NOTE: even if we run in read-only mode, we should be able to lock the
1064
mysql.event table for writing. In order to achieve this, we should call
1065
mysql_lock_tables() under the super user.
1068
saved_master_access= thd->security_ctx->master_access;
1069
thd->security_ctx->master_access |= SUPER_ACL;
1071
ret= db_repository->open_event_table(thd, TL_WRITE, &table);
1073
thd->security_ctx->master_access= saved_master_access;
1077
sql_print_error("Event Scheduler: Failed to open table mysql.event");
1081
if (init_read_record(&read_record_info, thd, table, NULL, 0, 1, FALSE))
1083
close_thread_tables(thd);
1087
while (!(read_record_info.read_record(&read_record_info)))
1089
Event_queue_element *et;
1091
bool drop_on_completion;
1093
if (!(et= new Event_queue_element))
1096
DBUG_PRINT("info", ("Loading event from row."));
1098
if (et->load_from_row(thd, table))
1100
sql_print_error("Event Scheduler: "
1101
"Error while loading events from mysql.event. "
1102
"The table probably contains bad data or is corrupted");
1106
drop_on_completion= (et->on_completion ==
1107
Event_parse_data::ON_COMPLETION_DROP);
1110
if (event_queue->create_event(thd, et, &created))
1118
else if (drop_on_completion)
1121
If not created, a stale event - drop if immediately if
1122
ON COMPLETION NOT PRESERVE.
1123
XXX: This won't be replicated, thus the drop won't appear in
1124
in the slave. When the slave is restarted it will drop events.
1125
However, as the slave will be "out of sync", it might happen that
1126
an event created on the master, after master restart, won't be
1127
replicated to the slave correctly, as the create will fail there.
1129
int rc= table->file->ha_delete_row(table->record[0]);
1132
table->file->print_error(rc, MYF(0));
1137
if (global_system_variables.log_warnings)
1138
sql_print_information("Event Scheduler: Loaded %d event%s",
1139
count, (count == 1) ? "" : "s");
1143
end_read_record(&read_record_info);
1145
close_mysql_tables(thd);
1150
@} (End of group Event_Scheduler)