2 Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
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
18 #include "mysql_priv.h"
20 #include "event_data_objects.h"
21 #include "event_db_repository.h"
22 #include "event_queue.h"
23 #include "event_scheduler.h"
24 #include "sp_head.h" // for Stored_program_creation_ctx
27 @addtogroup Event_Scheduler
33 - CREATE EVENT should not go into binary log! Does it now? The SQL statements
34 issued by the EVENT are replicated.
35 I have an idea how to solve the problem at failover. So the status field
36 will be ENUM('DISABLED', 'ENABLED', 'SLAVESIDE_DISABLED').
37 In this case when CREATE EVENT is replicated it should go into the binary
38 as SLAVESIDE_DISABLED if it is ENABLED, when it's created as DISABLEd it
39 should be replicated as disabled. If an event is ALTERed as DISABLED the
40 query should go untouched into the binary log, when ALTERed as enable then
41 it should go as SLAVESIDE_DISABLED. This is regarding the SQL interface.
42 TT routines however modify mysql.event internally and this does not go the
43 log so in this case queries has to be injected into the log...somehow... or
44 maybe a solution is RBR for this case, because the event may go only from
45 ENABLED to DISABLED status change and this is safe for replicating. As well
46 an event may be deleted which is also safe for RBR.
54 If the user (un)intentionally removes an event directly from mysql.event
55 the following sequence has to be used to be able to remove the in-memory
57 1. CREATE EVENT the_name ON SCHEDULE EVERY 1 SECOND DISABLE DO SELECT 1;
58 2. DROP EVENT the_name
60 In other words, the first one will create a row in mysql.event . In the
61 second step because there will be a line, disk based drop will pass and
62 the scheduler will remove the memory counterpart. The reason is that
63 in-memory queue does not check whether the event we try to drop from memory
64 is disabled. Disabled events are not kept in-memory because they are not
65 eligible for execution.
69 Keep the order of the first to as in var_typelib
70 sys_var_event_scheduler::value_ptr() references this array. Keep in
73 static const char *opt_event_scheduler_state_names
[]=
74 { "OFF", "ON", "0", "1", "DISABLED", NullS
};
76 const TYPELIB
Events::opt_typelib
=
78 array_elements(opt_event_scheduler_state_names
)-1,
80 opt_event_scheduler_state_names
,
86 The order should not be changed. We consider OFF to be equivalent of INT 0
87 And ON of 1. If OFF & ON are interchanged the logic in
88 sys_var_event_scheduler::update() will be broken!
90 static const char *var_event_scheduler_state_names
[]= { "OFF", "ON", NullS
};
92 const TYPELIB
Events::var_typelib
=
94 array_elements(var_event_scheduler_state_names
)-1,
96 var_event_scheduler_state_names
,
100 Event_queue
*Events::event_queue
;
101 Event_scheduler
*Events::scheduler
;
102 Event_db_repository
*Events::db_repository
;
103 enum Events::enum_opt_event_scheduler
104 Events::opt_event_scheduler
= Events::EVENTS_OFF
;
105 pthread_mutex_t
Events::LOCK_event_metadata
;
106 bool Events::check_system_tables_error
= FALSE
;
110 Compares 2 LEX strings regarding case.
124 int sortcmp_lex_string(LEX_STRING s
, LEX_STRING t
, CHARSET_INFO
*cs
)
126 return cs
->coll
->strnncollsp(cs
, (uchar
*) s
.str
,s
.length
,
127 (uchar
*) t
.str
,t
.length
, 0);
132 @brief Initialize the start up option of the Events scheduler.
134 Do not initialize the scheduler subsystem yet - the initialization
135 is split into steps as it has to fit into the common MySQL
136 initialization framework.
137 No locking as this is called only at start up.
139 @param[in,out] argument The value of the argument. If this value
140 is found in the typelib, the argument is
143 @retval TRUE unknown option value
144 @retval FALSE success
148 Events::set_opt_event_scheduler(char *argument
)
150 if (argument
== NULL
)
151 opt_event_scheduler
= Events::EVENTS_ON
;
157 (OFF | ON) - (0 | 1) (DISABLE )
159 const static enum enum_opt_event_scheduler type2state
[]=
160 { EVENTS_OFF
, EVENTS_ON
, EVENTS_OFF
, EVENTS_ON
, EVENTS_DISABLED
};
162 type
= find_type(argument
, &opt_typelib
, 1);
164 DBUG_ASSERT(type
>= 0 && type
<= 5); /* guaranteed by find_type */
168 fprintf(stderr
, "Unknown option to event-scheduler: %s\n", argument
);
171 opt_event_scheduler
= type2state
[type
-1];
178 Return a string representation of the current scheduler mode.
182 Events::get_opt_event_scheduler_str()
186 pthread_mutex_lock(&LOCK_event_metadata
);
187 str
= opt_typelib
.type_names
[(int) opt_event_scheduler
];
188 pthread_mutex_unlock(&LOCK_event_metadata
);
195 Push an error into the error stack if the system tables are
199 bool Events::check_if_system_tables_error()
201 DBUG_ENTER("Events::check_if_system_tables_error");
203 if (check_system_tables_error
)
205 my_error(ER_EVENTS_DB_ERROR
, MYF(0));
214 Reconstructs interval expression from interval type and expression
215 value that is in form of a value of the smalles entity:
217 YEAR_MONTH - expression is in months
218 DAY_MINUTE - expression is in minutes
221 Events::reconstruct_interval_expression()
222 buf Preallocated String buffer to add the value to
223 interval The interval type (for instance YEAR_MONTH)
224 expression The value in the lowest entity
232 Events::reconstruct_interval_expression(String
*buf
, interval_type interval
,
235 ulonglong expr
= expression
;
236 char tmp_buff
[128], *end
;
237 bool close_quote
= TRUE
;
242 case INTERVAL_YEAR_MONTH
:
245 goto common_1_lev_code
;
246 case INTERVAL_DAY_HOUR
:
249 goto common_1_lev_code
;
250 case INTERVAL_HOUR_MINUTE
:
251 case INTERVAL_MINUTE_SECOND
:
255 end
= longlong10_to_str(expression
/multipl
, tmp_buff
, 10);
256 buf
->append(tmp_buff
, (uint
) (end
- tmp_buff
));
257 expr
= expr
- (expr
/multipl
)*multipl
;
259 case INTERVAL_DAY_MINUTE
:
261 ulonglong tmp_expr
= expr
;
265 end
= longlong10_to_str(tmp_expr
, tmp_buff
, 10);
266 buf
->append(tmp_buff
, (uint
) (end
- tmp_buff
));// days
269 tmp_expr
= expr
- tmp_expr
*(24*60);//minutes left
270 end
= longlong10_to_str(tmp_expr
/60, tmp_buff
, 10);
271 buf
->append(tmp_buff
, (uint
) (end
- tmp_buff
));// hours
273 expr
= tmp_expr
- (tmp_expr
/60)*60;
274 /* the code after the switch will finish */
277 case INTERVAL_HOUR_SECOND
:
279 ulonglong tmp_expr
= expr
;
282 end
= longlong10_to_str(tmp_expr
/3600, tmp_buff
, 10);
283 buf
->append(tmp_buff
, (uint
) (end
- tmp_buff
));// hours
286 tmp_expr
= tmp_expr
- (tmp_expr
/3600)*3600;
287 end
= longlong10_to_str(tmp_expr
/60, tmp_buff
, 10);
288 buf
->append(tmp_buff
, (uint
) (end
- tmp_buff
));// minutes
290 expr
= tmp_expr
- (tmp_expr
/60)*60;
291 /* the code after the switch will finish */
294 case INTERVAL_DAY_SECOND
:
296 ulonglong tmp_expr
= expr
;
300 end
= longlong10_to_str(tmp_expr
, tmp_buff
, 10);
301 buf
->append(tmp_buff
, (uint
) (end
- tmp_buff
));// days
304 tmp_expr
= expr
- tmp_expr
*(24*3600);//seconds left
305 end
= longlong10_to_str(tmp_expr
/3600, tmp_buff
, 10);
306 buf
->append(tmp_buff
, (uint
) (end
- tmp_buff
));// hours
309 tmp_expr
= tmp_expr
- (tmp_expr
/3600)*3600;
310 end
= longlong10_to_str(tmp_expr
/60, tmp_buff
, 10);
311 buf
->append(tmp_buff
, (uint
) (end
- tmp_buff
));// minutes
313 expr
= tmp_expr
- (tmp_expr
/60)*60;
314 /* the code after the switch will finish */
317 case INTERVAL_DAY_MICROSECOND
:
318 case INTERVAL_HOUR_MICROSECOND
:
319 case INTERVAL_MINUTE_MICROSECOND
:
320 case INTERVAL_SECOND_MICROSECOND
:
321 case INTERVAL_MICROSECOND
:
322 my_error(ER_NOT_SUPPORTED_YET
, MYF(0), "MICROSECOND");
325 case INTERVAL_QUARTER
:
336 buf
->append(separator
);
337 end
= longlong10_to_str(expr
, tmp_buff
, 10);
338 buf
->append(tmp_buff
, (uint
) (end
- tmp_buff
));
347 Create a new query string for removing executable comments
348 for avoiding leak and keeping consistency of the execution
351 @param[in] thd Thread handler
352 @param[in] buf Query string
359 create_query_string(THD
*thd
, String
*buf
)
361 /* Append the "CREATE" part of the query */
362 if (buf
->append(STRING_WITH_LEN("CREATE ")))
365 append_definer(thd
, buf
, &(thd
->lex
->definer
->user
), &(thd
->lex
->definer
->host
));
366 /* Append the left part of thd->query after "DEFINER" part */
367 if (buf
->append(thd
->lex
->stmt_definition_begin
,
368 thd
->lex
->stmt_definition_end
-
369 thd
->lex
->stmt_definition_begin
))
379 @param[in,out] thd THD
380 @param[in] parse_data Event's data from parsing stage
381 @param[in] if_not_exists Whether IF NOT EXISTS was
383 In case there is an event with the same name (db) and
384 IF NOT EXISTS is specified, an warning is put into the stack.
385 @sa Events::drop_event for the notes about locking, pre-locking
389 @retval TRUE Error (reported)
393 Events::create_event(THD
*thd
, Event_parse_data
*parse_data
,
397 bool save_binlog_row_based
, event_already_exists
;
398 DBUG_ENTER("Events::create_event");
401 Let's commit the transaction first - MySQL manual specifies
402 that a DDL issues an implicit commit, and it doesn't say "successful
403 DDL", so that an implicit commit is a property of any successfully
404 parsed DDL statement.
406 if (end_active_trans(thd
))
409 if (check_if_system_tables_error())
413 Perform semantic checks outside of Event_db_repository:
414 once CREATE EVENT is supported in prepared statements, the
415 checks will be moved to PREPARE phase.
417 if (parse_data
->check_parse_data(thd
))
420 /* At create, one of them must be set */
421 DBUG_ASSERT(parse_data
->expression
|| parse_data
->execute_at
);
423 if (check_access(thd
, EVENT_ACL
, parse_data
->dbname
.str
, 0, 0, 0,
424 is_schema_db(parse_data
->dbname
.str
,
425 parse_data
->dbname
.length
)))
428 if (check_db_dir_existence(parse_data
->dbname
.str
))
430 my_error(ER_BAD_DB_ERROR
, MYF(0), parse_data
->dbname
.str
);
434 if (parse_data
->do_not_create
)
437 Turn off row binlogging of this statement and use statement-based
438 so that all supporting tables are updated for CREATE EVENT command.
440 save_binlog_row_based
= thd
->current_stmt_binlog_row_based
;
441 thd
->clear_current_stmt_binlog_row_based();
443 pthread_mutex_lock(&LOCK_event_metadata
);
445 /* On error conditions my_error() is called so no need to handle here */
446 if (!(ret
= db_repository
->create_event(thd
, parse_data
, if_not_exists
,
447 &event_already_exists
)))
449 Event_queue_element
*new_element
;
452 if (!event_already_exists
)
454 if (!(new_element
= new Event_queue_element()))
456 else if ((ret
= db_repository
->load_named_event(thd
, parse_data
->dbname
,
460 if (!db_repository
->drop_event(thd
, parse_data
->dbname
, parse_data
->name
,
467 /* TODO: do not ignore the out parameter and a possible OOM error! */
470 event_queue
->create_event(thd
, new_element
, &created
);
474 binlog the create event unless it's been successfully dropped
478 /* Binlog the create event. */
479 DBUG_ASSERT(thd
->query() && thd
->query_length());
481 if (create_query_string(thd
, &log_query
))
483 sql_print_error("Event Error: An error occurred while creating query string, "
484 "before writing it into binary log.");
489 If the definer is not set or set to CURRENT_USER, the value of CURRENT_USER
490 will be written into the binary log as the definer for the SQL thread.
492 ret
= write_bin_log(thd
, TRUE
, log_query
.c_ptr(), log_query
.length());
495 pthread_mutex_unlock(&LOCK_event_metadata
);
496 /* Restore the state of binlog format */
497 thd
->current_stmt_binlog_row_based
= save_binlog_row_based
;
506 @param[in,out] thd THD
507 @param[in] parse_data Event's data from parsing stage
508 @param[in] new_dbname A new schema name for the event. Set in the case of
509 ALTER EVENT RENAME, otherwise is NULL.
510 @param[in] new_name A new name for the event. Set in the case of
513 Parameter 'et' contains data about dbname and event name.
514 Parameter 'new_name' is the new name of the event, if not null
515 this means that RENAME TO was specified in the query
516 @sa Events::drop_event for the locking notes.
519 @retval TRUE error (reported)
523 Events::update_event(THD
*thd
, Event_parse_data
*parse_data
,
524 LEX_STRING
*new_dbname
, LEX_STRING
*new_name
)
527 bool save_binlog_row_based
;
528 Event_queue_element
*new_element
;
530 DBUG_ENTER("Events::update_event");
533 For consistency, implicit COMMIT should be the first thing in the
536 if (end_active_trans(thd
))
539 if (check_if_system_tables_error())
542 if (parse_data
->check_parse_data(thd
) || parse_data
->do_not_create
)
545 if (check_access(thd
, EVENT_ACL
, parse_data
->dbname
.str
, 0, 0, 0,
546 is_schema_db(parse_data
->dbname
.str
,
547 parse_data
->dbname
.length
)))
550 if (new_dbname
) /* It's a rename */
552 /* Check that the new and the old names differ. */
553 if ( !sortcmp_lex_string(parse_data
->dbname
, *new_dbname
,
554 system_charset_info
) &&
555 !sortcmp_lex_string(parse_data
->name
, *new_name
,
556 system_charset_info
))
558 my_error(ER_EVENT_SAME_NAME
, MYF(0));
563 And the user has sufficient privileges to use the target database.
564 Do it before checking whether the database exists: we don't want
565 to tell the user that a database doesn't exist if they can not
568 if (check_access(thd
, EVENT_ACL
, new_dbname
->str
, 0, 0, 0,
569 is_schema_db(new_dbname
->str
, new_dbname
->length
)))
572 /* Check that the target database exists */
573 if (check_db_dir_existence(new_dbname
->str
))
575 my_error(ER_BAD_DB_ERROR
, MYF(0), new_dbname
->str
);
581 Turn off row binlogging of this statement and use statement-based
582 so that all supporting tables are updated for UPDATE EVENT command.
584 save_binlog_row_based
= thd
->current_stmt_binlog_row_based
;
585 thd
->clear_current_stmt_binlog_row_based();
587 pthread_mutex_lock(&LOCK_event_metadata
);
589 /* On error conditions my_error() is called so no need to handle here */
590 if (!(ret
= db_repository
->update_event(thd
, parse_data
,
591 new_dbname
, new_name
)))
593 LEX_STRING dbname
= new_dbname
? *new_dbname
: parse_data
->dbname
;
594 LEX_STRING name
= new_name
? *new_name
: parse_data
->name
;
596 if (!(new_element
= new Event_queue_element()))
598 else if ((ret
= db_repository
->load_named_event(thd
, dbname
, name
,
601 DBUG_ASSERT(ret
== OP_LOAD_ERROR
);
607 TODO: check if an update actually has inserted an entry
609 If not, and the element is ON COMPLETION NOT PRESERVE, delete
613 event_queue
->update_event(thd
, parse_data
->dbname
, parse_data
->name
,
615 /* Binlog the alter event. */
616 DBUG_ASSERT(thd
->query() && thd
->query_length());
617 ret
= write_bin_log(thd
, TRUE
, thd
->query(), thd
->query_length());
620 pthread_mutex_unlock(&LOCK_event_metadata
);
621 /* Restore the state of binlog format */
622 thd
->current_stmt_binlog_row_based
= save_binlog_row_based
;
631 @param[in,out] thd THD
632 @param[in] dbname Event's schema
633 @param[in] name Event's name
634 @param[in] if_exists When this is set and the event does not exist
635 a warning is pushed into the warning stack.
636 Otherwise the operation produces an error.
638 @note Similarly to DROP PROCEDURE, we do not allow DROP EVENT
639 under LOCK TABLES mode, unless table mysql.event is locked. To
640 ensure that, we do not reset & backup the open tables state in
641 this function - if in LOCK TABLES or pre-locking mode, this will
642 lead to an error 'Table mysql.event is not locked with LOCK
643 TABLES' unless it _is_ locked. In pre-locked mode there is
644 another barrier - DROP EVENT commits the current transaction,
645 and COMMIT/ROLLBACK is not allowed in stored functions and
649 @retval TRUE Error (reported)
653 Events::drop_event(THD
*thd
, LEX_STRING dbname
, LEX_STRING name
, bool if_exists
)
656 bool save_binlog_row_based
;
657 DBUG_ENTER("Events::drop_event");
660 In MySQL, DDL must always commit: since mysql.* tables are
661 non-transactional, we must modify them outside a transaction
662 to not break atomicity.
663 But the second and more important reason to commit here
664 regardless whether we're actually changing mysql.event table
665 or not is replication: end_active_trans syncs the binary log,
666 and unless we run DDL in it's own transaction it may simply
667 never appear on the slave in case the outside transaction
670 if (end_active_trans(thd
))
673 if (check_if_system_tables_error())
676 if (check_access(thd
, EVENT_ACL
, dbname
.str
, 0, 0, 0,
677 is_schema_db(dbname
.str
, dbname
.length
)))
681 Turn off row binlogging of this statement and use statement-based so
682 that all supporting tables are updated for DROP EVENT command.
684 save_binlog_row_based
= thd
->current_stmt_binlog_row_based
;
685 thd
->clear_current_stmt_binlog_row_based();
687 pthread_mutex_lock(&LOCK_event_metadata
);
688 /* On error conditions my_error() is called so no need to handle here */
689 if (!(ret
= db_repository
->drop_event(thd
, dbname
, name
, if_exists
)))
692 event_queue
->drop_event(thd
, dbname
, name
);
693 /* Binlog the drop event. */
694 DBUG_ASSERT(thd
->query() && thd
->query_length());
695 ret
= write_bin_log(thd
, TRUE
, thd
->query(), thd
->query_length());
697 pthread_mutex_unlock(&LOCK_event_metadata
);
698 /* Restore the state of binlog format */
699 thd
->current_stmt_binlog_row_based
= save_binlog_row_based
;
705 Drops all events from a schema
707 @note We allow to drop all events in a schema even if the
708 scheduler is disabled. This is to not produce any warnings
709 in case of DROP DATABASE and a disabled scheduler.
711 @param[in,out] thd Thread
712 @param[in] db ASCIIZ schema name
716 Events::drop_schema_events(THD
*thd
, char *db
)
718 LEX_STRING
const db_lex
= { db
, strlen(db
) };
720 DBUG_ENTER("Events::drop_schema_events");
721 DBUG_PRINT("enter", ("dropping events from %s", db
));
724 sic: no check if the scheduler is disabled or system tables
725 are damaged, as intended.
728 pthread_mutex_lock(&LOCK_event_metadata
);
730 event_queue
->drop_schema_events(thd
, db_lex
);
731 db_repository
->drop_schema_events(thd
, db_lex
);
732 pthread_mutex_unlock(&LOCK_event_metadata
);
739 A helper function to generate SHOW CREATE EVENT output from
744 send_show_create_event(THD
*thd
, Event_timed
*et
, Protocol
*protocol
)
746 char show_str_buf
[10 * STRING_BUFFER_USUAL_SIZE
];
747 String
show_str(show_str_buf
, sizeof(show_str_buf
), system_charset_info
);
748 List
<Item
> field_list
;
750 const String
*tz_name
;
752 DBUG_ENTER("send_show_create_event");
755 if (et
->get_create_event(thd
, &show_str
))
758 field_list
.push_back(new Item_empty_string("Event", NAME_CHAR_LEN
));
760 if (sys_var_thd_sql_mode::symbolic_mode_representation(thd
, et
->sql_mode
,
764 field_list
.push_back(new Item_empty_string("sql_mode", (uint
) sql_mode
.length
));
766 tz_name
= et
->time_zone
->get_name();
768 field_list
.push_back(new Item_empty_string("time_zone",
771 field_list
.push_back(new Item_empty_string("Create Event",
774 field_list
.push_back(
775 new Item_empty_string("character_set_client", MY_CS_NAME_SIZE
));
777 field_list
.push_back(
778 new Item_empty_string("collation_connection", MY_CS_NAME_SIZE
));
780 field_list
.push_back(
781 new Item_empty_string("Database Collation", MY_CS_NAME_SIZE
));
783 if (protocol
->send_fields(&field_list
,
784 Protocol::SEND_NUM_ROWS
| Protocol::SEND_EOF
))
787 protocol
->prepare_for_resend();
789 protocol
->store(et
->name
.str
, et
->name
.length
, system_charset_info
);
790 protocol
->store(sql_mode
.str
, sql_mode
.length
, system_charset_info
);
791 protocol
->store(tz_name
->ptr(), tz_name
->length(), system_charset_info
);
792 protocol
->store(show_str
.c_ptr(), show_str
.length(),
793 et
->creation_ctx
->get_client_cs());
794 protocol
->store(et
->creation_ctx
->get_client_cs()->csname
,
795 strlen(et
->creation_ctx
->get_client_cs()->csname
),
796 system_charset_info
);
797 protocol
->store(et
->creation_ctx
->get_connection_cl()->name
,
798 strlen(et
->creation_ctx
->get_connection_cl()->name
),
799 system_charset_info
);
800 protocol
->store(et
->creation_ctx
->get_db_cl()->name
,
801 strlen(et
->creation_ctx
->get_db_cl()->name
),
802 system_charset_info
);
804 if (protocol
->write())
814 Implement SHOW CREATE EVENT statement
817 spn The name of the event (db, name)
820 @retval TRUE error (reported)
824 Events::show_create_event(THD
*thd
, LEX_STRING dbname
, LEX_STRING name
)
826 Open_tables_state open_tables_backup
;
830 DBUG_ENTER("Events::show_create_event");
831 DBUG_PRINT("enter", ("name: %s@%s", dbname
.str
, name
.str
));
833 if (check_if_system_tables_error())
836 if (check_access(thd
, EVENT_ACL
, dbname
.str
, 0, 0, 0,
837 is_schema_db(dbname
.str
, dbname
.length
)))
841 We would like to allow SHOW CREATE EVENT under LOCK TABLES and
842 in pre-locked mode. mysql.event table is marked as a system table.
843 This flag reduces the set of its participation scenarios in LOCK TABLES
844 operation, and therefore an out-of-bound open of this table
845 for reading like the one below (sic, only for reading) is
846 more or less deadlock-free. For additional information about when a
847 deadlock can occur please refer to the description of 'system table'
850 thd
->reset_n_backup_open_tables_state(&open_tables_backup
);
851 ret
= db_repository
->load_named_event(thd
, dbname
, name
, &et
);
852 thd
->restore_backup_open_tables_state(&open_tables_backup
);
855 ret
= send_show_create_event(thd
, &et
, thd
->protocol
);
862 Check access rights and fill INFORMATION_SCHEMA.events table.
864 @param[in,out] thd Thread context
865 @param[in] tables The temporary table to fill.
867 In MySQL INFORMATION_SCHEMA tables are temporary tables that are
868 created and filled on demand. In this function, we fill
869 INFORMATION_SCHEMA.events. It is a callback for I_S module, invoked from
872 @return Has to be integer, as such is the requirement of the I_S API
874 @retval 1 an error, pushed into the error stack
878 Events::fill_schema_events(THD
*thd
, TABLE_LIST
*tables
, COND
* /* cond */)
882 Open_tables_state open_tables_backup
;
883 DBUG_ENTER("Events::fill_schema_events");
885 if (check_if_system_tables_error())
889 If it's SHOW EVENTS then thd->lex->select_lex.db is guaranteed not to
890 be NULL. Let's do an assert anyway.
892 if (thd
->lex
->sql_command
== SQLCOM_SHOW_EVENTS
)
894 DBUG_ASSERT(thd
->lex
->select_lex
.db
);
895 if (!is_schema_db(thd
->lex
->select_lex
.db
) && // There is no events in I_S
896 check_access(thd
, EVENT_ACL
, thd
->lex
->select_lex
.db
, 0, 0, 0, 0))
898 db
= thd
->lex
->select_lex
.db
;
901 Reset and backup of the currently open tables in this thread
902 is a way to allow SELECTs from INFORMATION_SCHEMA.events under
903 LOCK TABLES and in pre-locked mode. See also
904 Events::show_create_event for additional comments.
906 thd
->reset_n_backup_open_tables_state(&open_tables_backup
);
907 ret
= db_repository
->fill_schema_events(thd
, tables
, db
);
908 thd
->restore_backup_open_tables_state(&open_tables_backup
);
915 Initializes the scheduler's structures.
917 @param opt_noacl_or_bootstrap
918 TRUE if there is --skip-grant-tables or --bootstrap
919 option. In that case we disable the event scheduler.
921 @note This function is not synchronized.
923 @retval FALSE Perhaps there was an error, and the event scheduler
924 is disabled. But the error is not fatal and the
925 server start up can continue.
926 @retval TRUE Fatal error. Startup must terminate (call unireg_abort()).
930 Events::init(my_bool opt_noacl_or_bootstrap
)
936 DBUG_ENTER("Events::init");
938 /* We need a temporary THD during boot */
939 if (!(thd
= new THD()))
945 The thread stack does not start from this function but we cannot
946 guess the real value. So better some value that doesn't assert than
949 thd
->thread_stack
= (char*) &thd
;
950 thd
->store_globals();
954 We will need Event_db_repository anyway, even if the scheduler is
955 disabled - to perform events DDL.
957 if (!(db_repository
= new Event_db_repository
))
959 res
= TRUE
; /* fatal error: request unireg_abort */
964 Since we allow event DDL even if the scheduler is disabled,
965 check the system tables, as we might need them.
967 If run with --skip-grant-tables or --bootstrap, don't try to do the
968 check of system tables and don't complain: in these modes the tables
969 are most likely not there and we're going to disable the event
972 if (opt_noacl_or_bootstrap
|| Event_db_repository::check_system_tables(thd
))
974 if (! opt_noacl_or_bootstrap
)
976 sql_print_error("Event Scheduler: An error occurred when initializing "
977 "system tables. Disabling the Event Scheduler.");
978 check_system_tables_error
= TRUE
;
981 /* Disable the scheduler since the system tables are not up to date */
982 opt_event_scheduler
= EVENTS_DISABLED
;
987 Was disabled explicitly from the command line, or because we're running
988 with --skip-grant-tables, or --bootstrap, or because we have no system
991 if (opt_event_scheduler
== Events::EVENTS_DISABLED
)
995 DBUG_ASSERT(opt_event_scheduler
== Events::EVENTS_ON
||
996 opt_event_scheduler
== Events::EVENTS_OFF
);
998 if (!(event_queue
= new Event_queue
) ||
999 !(scheduler
= new Event_scheduler(event_queue
)))
1001 res
= TRUE
; /* fatal error: request unireg_abort */
1005 if (event_queue
->init_queue(thd
) || load_events_from_db(thd
) ||
1006 (opt_event_scheduler
== EVENTS_ON
&& scheduler
->start()))
1008 sql_print_error("Event Scheduler: Error while loading from disk.");
1009 res
= TRUE
; /* fatal error: request unireg_abort */
1012 Event_worker_thread::init(db_repository
);
1017 delete db_repository
;
1022 /* Remember that we don't have a THD */
1023 my_pthread_setspecific_ptr(THR_THD
, NULL
);
1029 Cleans up scheduler's resources. Called at server shutdown.
1035 This function is not synchronized.
1041 DBUG_ENTER("Events::deinit");
1043 if (opt_event_scheduler
!= EVENTS_DISABLED
)
1046 scheduler
= NULL
; /* safety */
1048 event_queue
= NULL
; /* safety */
1051 delete db_repository
;
1052 db_repository
= NULL
; /* safety */
1059 Inits Events mutexes
1062 Events::init_mutexes()
1067 Events::init_mutexes()
1069 pthread_mutex_init(&LOCK_event_metadata
, MY_MUTEX_INIT_FAST
);
1074 Destroys Events mutexes
1077 Events::destroy_mutexes()
1081 Events::destroy_mutexes()
1083 pthread_mutex_destroy(&LOCK_event_metadata
);
1088 Dumps the internal status of the scheduler and the memory cache
1089 into a table with two columns - Name & Value. Different properties
1090 which could be useful for debugging for instance deadlocks are
1094 Events::dump_internal_status()
1098 Events::dump_internal_status()
1100 DBUG_ENTER("Events::dump_internal_status");
1101 puts("\n\n\nEvents status:");
1102 puts("LLA = Last Locked At LUA = Last Unlocked At");
1103 puts("WOC = Waiting On Condition DL = Data Locked");
1105 pthread_mutex_lock(&LOCK_event_metadata
);
1106 if (opt_event_scheduler
== EVENTS_DISABLED
)
1107 puts("The Event Scheduler is disabled");
1110 scheduler
->dump_internal_status();
1111 event_queue
->dump_internal_status();
1114 pthread_mutex_unlock(&LOCK_event_metadata
);
1120 Starts or stops the event scheduler thread.
1122 @retval FALSE success
1127 Events::switch_event_scheduler_state(enum_opt_event_scheduler new_state
)
1131 DBUG_ENTER("Events::switch_event_scheduler_state");
1133 DBUG_ASSERT(new_state
== Events::EVENTS_ON
||
1134 new_state
== Events::EVENTS_OFF
);
1137 If the scheduler was disabled because there are no/bad
1138 system tables, produce a more meaningful error message
1139 than ER_OPTION_PREVENTS_STATEMENT
1141 if (check_if_system_tables_error())
1144 pthread_mutex_lock(&LOCK_event_metadata
);
1146 if (opt_event_scheduler
== EVENTS_DISABLED
)
1148 my_error(ER_OPTION_PREVENTS_STATEMENT
,
1149 MYF(0), "--event-scheduler=DISABLED or --skip-grant-tables");
1154 if (new_state
== EVENTS_ON
)
1155 ret
= scheduler
->start();
1157 ret
= scheduler
->stop();
1161 my_error(ER_EVENT_SET_VAR_ERROR
, MYF(0), 0);
1165 opt_event_scheduler
= new_state
;
1168 pthread_mutex_unlock(&LOCK_event_metadata
);
1174 Loads all ENABLED events from mysql.event into a prioritized
1177 This function is called during the server start up. It reads
1178 every event, computes the next execution time, and if the event
1179 needs execution, adds it to a prioritized queue. Otherwise, if
1180 ON COMPLETION DROP is specified, the event is automatically
1181 removed from the table.
1183 @param[in,out] thd Thread context. Used for memory allocation in some cases.
1185 @retval FALSE success
1186 @retval TRUE error, the load is aborted
1188 @note Reports the error to the console
1192 Events::load_events_from_db(THD
*thd
)
1195 READ_RECORD read_record_info
;
1198 ulong saved_master_access
;
1200 DBUG_ENTER("Events::load_events_from_db");
1201 DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd
));
1204 NOTE: even if we run in read-only mode, we should be able to lock the
1205 mysql.event table for writing. In order to achieve this, we should call
1206 mysql_lock_tables() under the super user.
1209 saved_master_access
= thd
->security_ctx
->master_access
;
1210 thd
->security_ctx
->master_access
|= SUPER_ACL
;
1212 ret
= db_repository
->open_event_table(thd
, TL_WRITE
, &table
);
1214 thd
->security_ctx
->master_access
= saved_master_access
;
1218 sql_print_error("Event Scheduler: Failed to open table mysql.event");
1222 init_read_record(&read_record_info
, thd
, table
, NULL
, 0, 1, FALSE
);
1223 while (!(read_record_info
.read_record(&read_record_info
)))
1225 Event_queue_element
*et
;
1227 bool drop_on_completion
;
1229 if (!(et
= new Event_queue_element
))
1232 DBUG_PRINT("info", ("Loading event from row."));
1234 if (et
->load_from_row(thd
, table
))
1236 sql_print_error("Event Scheduler: "
1237 "Error while loading events from mysql.event. "
1238 "The table probably contains bad data or is corrupted");
1242 drop_on_completion
= (et
->on_completion
==
1243 Event_parse_data::ON_COMPLETION_DROP
);
1246 if (event_queue
->create_event(thd
, et
, &created
))
1254 else if (drop_on_completion
)
1257 If not created, a stale event - drop if immediately if
1258 ON COMPLETION NOT PRESERVE.
1259 XXX: This won't be replicated, thus the drop won't appear in
1260 in the slave. When the slave is restarted it will drop events.
1261 However, as the slave will be "out of sync", it might happen that
1262 an event created on the master, after master restart, won't be
1263 replicated to the slave correctly, as the create will fail there.
1265 int rc
= table
->file
->ha_delete_row(table
->record
[0]);
1268 table
->file
->print_error(rc
, MYF(0));
1273 sql_print_information("Event Scheduler: Loaded %d event%s",
1274 count
, (count
== 1) ? "" : "s");
1278 end_read_record(&read_record_info
);
1280 close_thread_tables(thd
);
1286 @} (End of group Event_Scheduler)