mySQL 5.0.11 sources for tomato
[tomato.git] / release / src / router / mysql / sql / events.cc
blob1820b59455574939f8f64761fbd184438e6f3eaa
1 /*
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"
19 #include "events.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
26 /**
27 @addtogroup Event_Scheduler
32 TODO list :
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.
48 - Add logging to file
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
56 counterpart.
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
71 mind!
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,
79 "",
80 opt_event_scheduler_state_names,
81 NULL
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,
95 "",
96 var_event_scheduler_state_names,
97 NULL
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.
112 SYNOPSIS
113 sortcmp_lex_string()
114 s First LEX_STRING
115 t Second LEX_STRING
116 cs Charset
118 RETURN VALUE
119 -1 s < t
120 0 s == t
121 1 s > t
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
141 updated.
143 @retval TRUE unknown option value
144 @retval FALSE success
147 bool
148 Events::set_opt_event_scheduler(char *argument)
150 if (argument == NULL)
151 opt_event_scheduler= Events::EVENTS_ON;
152 else
154 int type;
156 type= 1 2 3 4 5
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 */
166 if (type == 0)
168 fprintf(stderr, "Unknown option to event-scheduler: %s\n", argument);
169 return TRUE;
171 opt_event_scheduler= type2state[type-1];
173 return FALSE;
178 Return a string representation of the current scheduler mode.
181 const char *
182 Events::get_opt_event_scheduler_str()
184 const char *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);
190 return str;
195 Push an error into the error stack if the system tables are
196 not up to date.
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));
206 DBUG_RETURN(TRUE);
209 DBUG_RETURN(FALSE);
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
220 SYNOPSIS
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
226 RETURN VALUE
227 0 OK
228 1 Error
232 Events::reconstruct_interval_expression(String *buf, interval_type interval,
233 longlong expression)
235 ulonglong expr= expression;
236 char tmp_buff[128], *end;
237 bool close_quote= TRUE;
238 int multipl= 0;
239 char separator=':';
241 switch (interval) {
242 case INTERVAL_YEAR_MONTH:
243 multipl= 12;
244 separator= '-';
245 goto common_1_lev_code;
246 case INTERVAL_DAY_HOUR:
247 multipl= 24;
248 separator= ' ';
249 goto common_1_lev_code;
250 case INTERVAL_HOUR_MINUTE:
251 case INTERVAL_MINUTE_SECOND:
252 multipl= 60;
253 common_1_lev_code:
254 buf->append('\'');
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;
258 break;
259 case INTERVAL_DAY_MINUTE:
261 ulonglong tmp_expr= expr;
263 tmp_expr/=(24*60);
264 buf->append('\'');
265 end= longlong10_to_str(tmp_expr, tmp_buff, 10);
266 buf->append(tmp_buff, (uint) (end- tmp_buff));// days
267 buf->append(' ');
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 */
276 break;
277 case INTERVAL_HOUR_SECOND:
279 ulonglong tmp_expr= expr;
281 buf->append('\'');
282 end= longlong10_to_str(tmp_expr/3600, tmp_buff, 10);
283 buf->append(tmp_buff, (uint) (end- tmp_buff));// hours
284 buf->append(':');
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 */
293 break;
294 case INTERVAL_DAY_SECOND:
296 ulonglong tmp_expr= expr;
298 tmp_expr/=(24*3600);
299 buf->append('\'');
300 end= longlong10_to_str(tmp_expr, tmp_buff, 10);
301 buf->append(tmp_buff, (uint) (end- tmp_buff));// days
302 buf->append(' ');
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
307 buf->append(':');
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 */
316 break;
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");
323 return 1;
324 break;
325 case INTERVAL_QUARTER:
326 expr/= 3;
327 close_quote= FALSE;
328 break;
329 case INTERVAL_WEEK:
330 expr/= 7;
331 default:
332 close_quote= FALSE;
333 break;
335 if (close_quote)
336 buf->append(separator);
337 end= longlong10_to_str(expr, tmp_buff, 10);
338 buf->append(tmp_buff, (uint) (end- tmp_buff));
339 if (close_quote)
340 buf->append('\'');
342 return 0;
347 Create a new query string for removing executable comments
348 for avoiding leak and keeping consistency of the execution
349 on master and slave.
351 @param[in] thd Thread handler
352 @param[in] buf Query string
354 @return
355 0 ok
356 1 error
358 static int
359 create_query_string(THD *thd, String *buf)
361 /* Append the "CREATE" part of the query */
362 if (buf->append(STRING_WITH_LEN("CREATE ")))
363 return 1;
364 /* Append definer */
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))
370 return 1;
372 return 0;
377 Create a new event.
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
382 specified
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
386 and Events DDL.
388 @retval FALSE OK
389 @retval TRUE Error (reported)
392 bool
393 Events::create_event(THD *thd, Event_parse_data *parse_data,
394 bool if_not_exists)
396 bool ret;
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))
407 DBUG_RETURN(TRUE);
409 if (check_if_system_tables_error())
410 DBUG_RETURN(TRUE);
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))
418 DBUG_RETURN(TRUE);
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)))
426 DBUG_RETURN(TRUE);
428 if (check_db_dir_existence(parse_data->dbname.str))
430 my_error(ER_BAD_DB_ERROR, MYF(0), parse_data->dbname.str);
431 DBUG_RETURN(TRUE);
434 if (parse_data->do_not_create)
435 DBUG_RETURN(FALSE);
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;
450 bool dropped= 0;
452 if (!event_already_exists)
454 if (!(new_element= new Event_queue_element()))
455 ret= TRUE; // OOM
456 else if ((ret= db_repository->load_named_event(thd, parse_data->dbname,
457 parse_data->name,
458 new_element)))
460 if (!db_repository->drop_event(thd, parse_data->dbname, parse_data->name,
461 TRUE))
462 dropped= 1;
463 delete new_element;
465 else
467 /* TODO: do not ignore the out parameter and a possible OOM error! */
468 bool created;
469 if (event_queue)
470 event_queue->create_event(thd, new_element, &created);
474 binlog the create event unless it's been successfully dropped
476 if (!dropped)
478 /* Binlog the create event. */
479 DBUG_ASSERT(thd->query() && thd->query_length());
480 String log_query;
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.");
485 ret= true;
487 else
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;
499 DBUG_RETURN(ret);
504 Alter an event.
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
511 ALTER EVENT RENAME
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.
518 @retval FALSE OK
519 @retval TRUE error (reported)
522 bool
523 Events::update_event(THD *thd, Event_parse_data *parse_data,
524 LEX_STRING *new_dbname, LEX_STRING *new_name)
526 int ret;
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
534 execution chain.
536 if (end_active_trans(thd))
537 DBUG_RETURN(TRUE);
539 if (check_if_system_tables_error())
540 DBUG_RETURN(TRUE);
542 if (parse_data->check_parse_data(thd) || parse_data->do_not_create)
543 DBUG_RETURN(TRUE);
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)))
548 DBUG_RETURN(TRUE);
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));
559 DBUG_RETURN(TRUE);
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
566 access it.
568 if (check_access(thd, EVENT_ACL, new_dbname->str, 0, 0, 0,
569 is_schema_db(new_dbname->str, new_dbname->length)))
570 DBUG_RETURN(TRUE);
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);
576 DBUG_RETURN(TRUE);
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()))
597 ret= TRUE; // OOM
598 else if ((ret= db_repository->load_named_event(thd, dbname, name,
599 new_element)))
601 DBUG_ASSERT(ret == OP_LOAD_ERROR);
602 delete new_element;
604 else
607 TODO: check if an update actually has inserted an entry
608 into the queue.
609 If not, and the element is ON COMPLETION NOT PRESERVE, delete
610 it right away.
612 if (event_queue)
613 event_queue->update_event(thd, parse_data->dbname, parse_data->name,
614 new_element);
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;
624 DBUG_RETURN(ret);
629 Drops an event
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
646 triggers.
648 @retval FALSE OK
649 @retval TRUE Error (reported)
652 bool
653 Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists)
655 int ret;
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
668 rolls back.
670 if (end_active_trans(thd))
671 DBUG_RETURN(TRUE);
673 if (check_if_system_tables_error())
674 DBUG_RETURN(TRUE);
676 if (check_access(thd, EVENT_ACL, dbname.str, 0, 0, 0,
677 is_schema_db(dbname.str, dbname.length)))
678 DBUG_RETURN(TRUE);
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)))
691 if (event_queue)
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;
700 DBUG_RETURN(ret);
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
715 void
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);
729 if (event_queue)
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);
734 DBUG_VOID_RETURN;
739 A helper function to generate SHOW CREATE EVENT output from
740 a named event
743 static bool
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;
749 LEX_STRING sql_mode;
750 const String *tz_name;
752 DBUG_ENTER("send_show_create_event");
754 show_str.length(0);
755 if (et->get_create_event(thd, &show_str))
756 DBUG_RETURN(TRUE);
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,
761 &sql_mode))
762 DBUG_RETURN(TRUE);
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",
769 tz_name->length()));
771 field_list.push_back(new Item_empty_string("Create Event",
772 show_str.length()));
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))
785 DBUG_RETURN(TRUE);
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())
805 DBUG_RETURN(TRUE);
807 my_eof(thd);
809 DBUG_RETURN(FALSE);
814 Implement SHOW CREATE EVENT statement
816 thd Thread context
817 spn The name of the event (db, name)
819 @retval FALSE OK
820 @retval TRUE error (reported)
823 bool
824 Events::show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
826 Open_tables_state open_tables_backup;
827 Event_timed et;
828 bool ret;
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())
834 DBUG_RETURN(TRUE);
836 if (check_access(thd, EVENT_ACL, dbname.str, 0, 0, 0,
837 is_schema_db(dbname.str, dbname.length)))
838 DBUG_RETURN(TRUE);
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'
848 flag.
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);
854 if (!ret)
855 ret= send_show_create_event(thd, &et, thd->protocol);
857 DBUG_RETURN(ret);
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
870 sql_show.cc
872 @return Has to be integer, as such is the requirement of the I_S API
873 @retval 0 success
874 @retval 1 an error, pushed into the error stack
878 Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
880 char *db= NULL;
881 int ret;
882 Open_tables_state open_tables_backup;
883 DBUG_ENTER("Events::fill_schema_events");
885 if (check_if_system_tables_error())
886 DBUG_RETURN(1);
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))
897 DBUG_RETURN(1);
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);
910 DBUG_RETURN(ret);
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()).
929 bool
930 Events::init(my_bool opt_noacl_or_bootstrap)
933 THD *thd;
934 bool res= FALSE;
936 DBUG_ENTER("Events::init");
938 /* We need a temporary THD during boot */
939 if (!(thd= new THD()))
941 res= TRUE;
942 goto end;
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
947 no value.
949 thd->thread_stack= (char*) &thd;
950 thd->store_globals();
951 lex_start(thd);
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 */
960 goto end;
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
970 scheduler anyway.
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;
983 goto end;
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
989 tables.
991 if (opt_event_scheduler == Events::EVENTS_DISABLED)
992 goto end;
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 */
1002 goto end;
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 */
1010 goto end;
1012 Event_worker_thread::init(db_repository);
1014 end:
1015 if (res)
1017 delete db_repository;
1018 delete event_queue;
1019 delete scheduler;
1021 delete thd;
1022 /* Remember that we don't have a THD */
1023 my_pthread_setspecific_ptr(THR_THD, NULL);
1025 DBUG_RETURN(res);
1029 Cleans up scheduler's resources. Called at server shutdown.
1031 SYNOPSIS
1032 Events::deinit()
1034 NOTES
1035 This function is not synchronized.
1038 void
1039 Events::deinit()
1041 DBUG_ENTER("Events::deinit");
1043 if (opt_event_scheduler != EVENTS_DISABLED)
1045 delete scheduler;
1046 scheduler= NULL; /* safety */
1047 delete event_queue;
1048 event_queue= NULL; /* safety */
1051 delete db_repository;
1052 db_repository= NULL; /* safety */
1054 DBUG_VOID_RETURN;
1059 Inits Events mutexes
1061 SYNOPSIS
1062 Events::init_mutexes()
1063 thd Thread
1066 void
1067 Events::init_mutexes()
1069 pthread_mutex_init(&LOCK_event_metadata, MY_MUTEX_INIT_FAST);
1074 Destroys Events mutexes
1076 SYNOPSIS
1077 Events::destroy_mutexes()
1080 void
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
1091 returned.
1093 SYNOPSIS
1094 Events::dump_internal_status()
1097 void
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");
1108 else
1110 scheduler->dump_internal_status();
1111 event_queue->dump_internal_status();
1114 pthread_mutex_unlock(&LOCK_event_metadata);
1115 DBUG_VOID_RETURN;
1120 Starts or stops the event scheduler thread.
1122 @retval FALSE success
1123 @retval TRUE error
1126 bool
1127 Events::switch_event_scheduler_state(enum_opt_event_scheduler new_state)
1129 bool ret= FALSE;
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())
1142 DBUG_RETURN(TRUE);
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");
1150 ret= TRUE;
1151 goto end;
1154 if (new_state == EVENTS_ON)
1155 ret= scheduler->start();
1156 else
1157 ret= scheduler->stop();
1159 if (ret)
1161 my_error(ER_EVENT_SET_VAR_ERROR, MYF(0), 0);
1162 goto end;
1165 opt_event_scheduler= new_state;
1167 end:
1168 pthread_mutex_unlock(&LOCK_event_metadata);
1169 DBUG_RETURN(ret);
1174 Loads all ENABLED events from mysql.event into a prioritized
1175 queue.
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
1191 bool
1192 Events::load_events_from_db(THD *thd)
1194 TABLE *table;
1195 READ_RECORD read_record_info;
1196 bool ret= TRUE;
1197 uint count= 0;
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;
1216 if (ret)
1218 sql_print_error("Event Scheduler: Failed to open table mysql.event");
1219 DBUG_RETURN(TRUE);
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;
1226 bool created;
1227 bool drop_on_completion;
1229 if (!(et= new Event_queue_element))
1230 goto end;
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");
1239 delete et;
1240 goto end;
1242 drop_on_completion= (et->on_completion ==
1243 Event_parse_data::ON_COMPLETION_DROP);
1246 if (event_queue->create_event(thd, et, &created))
1248 /* Out of memory */
1249 delete et;
1250 goto end;
1252 if (created)
1253 count++;
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]);
1266 if (rc)
1268 table->file->print_error(rc, MYF(0));
1269 goto end;
1273 sql_print_information("Event Scheduler: Loaded %d event%s",
1274 count, (count == 1) ? "" : "s");
1275 ret= FALSE;
1277 end:
1278 end_read_record(&read_record_info);
1280 close_thread_tables(thd);
1282 DBUG_RETURN(ret);
1286 @} (End of group Event_Scheduler)