MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
events.cc
1 /*
2  Copyright (c) 2005, 2011, Oracle and/or its affiliates. All rights reserved.
3 
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.
7 
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.
12 
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 */
16 
17 #include "sql_priv.h"
18 #include "unireg.h"
19 #include "sql_parse.h" // check_access
20 #include "sql_base.h" // close_mysql_tables
21 #include "sql_show.h" // append_definer
22 #include "events.h"
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
33 #include "set_var.h"
34 #include "lock.h" // lock_object_name
35 
41 /*
42  TODO list :
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.
57 
58  - Add logging to file
59 
60 */
61 
62 
63 /*
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
66  counterpart.
67  1. CREATE EVENT the_name ON SCHEDULE EVERY 1 SECOND DISABLE DO SELECT 1;
68  2. DROP EVENT the_name
69 
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.
76 */
77 
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;
83 
84 
85 /*
86  Compares 2 LEX strings regarding case.
87 
88  SYNOPSIS
89  sortcmp_lex_string()
90  s First LEX_STRING
91  t Second LEX_STRING
92  cs Charset
93 
94  RETURN VALUE
95  -1 s < t
96  0 s == t
97  1 s > t
98 */
99 
100 int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
101 {
102  return cs->coll->strnncollsp(cs, (uchar *) s.str,s.length,
103  (uchar *) t.str,t.length, 0);
104 }
105 
106 
113 {
114  DBUG_ENTER("Events::check_if_system_tables_error");
115 
116  if (check_system_tables_error)
117  {
118  my_error(ER_EVENTS_DB_ERROR, MYF(0));
119  DBUG_RETURN(TRUE);
120  }
121 
122  DBUG_RETURN(FALSE);
123 }
124 
125 
144 int
146  longlong expression)
147 {
148  ulonglong expr= expression;
149  char tmp_buff[128], *end;
150  bool close_quote= TRUE;
151  int multipl= 0;
152  char separator=':';
153 
154  switch (interval) {
155  case INTERVAL_YEAR_MONTH:
156  multipl= 12;
157  separator= '-';
158  goto common_1_lev_code;
159  case INTERVAL_DAY_HOUR:
160  multipl= 24;
161  separator= ' ';
162  goto common_1_lev_code;
163  case INTERVAL_HOUR_MINUTE:
164  case INTERVAL_MINUTE_SECOND:
165  multipl= 60;
166 common_1_lev_code:
167  buf->append('\'');
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;
171  break;
172  case INTERVAL_DAY_MINUTE:
173  {
174  ulonglong tmp_expr= expr;
175 
176  tmp_expr/=(24*60);
177  buf->append('\'');
178  end= longlong10_to_str(tmp_expr, tmp_buff, 10);
179  buf->append(tmp_buff, (uint) (end- tmp_buff));// days
180  buf->append(' ');
181 
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
185 
186  expr= tmp_expr - (tmp_expr/60)*60;
187  /* the code after the switch will finish */
188  }
189  break;
190  case INTERVAL_HOUR_SECOND:
191  {
192  ulonglong tmp_expr= expr;
193 
194  buf->append('\'');
195  end= longlong10_to_str(tmp_expr/3600, tmp_buff, 10);
196  buf->append(tmp_buff, (uint) (end- tmp_buff));// hours
197  buf->append(':');
198 
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
202 
203  expr= tmp_expr - (tmp_expr/60)*60;
204  /* the code after the switch will finish */
205  }
206  break;
207  case INTERVAL_DAY_SECOND:
208  {
209  ulonglong tmp_expr= expr;
210 
211  tmp_expr/=(24*3600);
212  buf->append('\'');
213  end= longlong10_to_str(tmp_expr, tmp_buff, 10);
214  buf->append(tmp_buff, (uint) (end- tmp_buff));// days
215  buf->append(' ');
216 
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
220  buf->append(':');
221 
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
225 
226  expr= tmp_expr - (tmp_expr/60)*60;
227  /* the code after the switch will finish */
228  }
229  break;
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");
236  return 1;
237  break;
238  case INTERVAL_QUARTER:
239  expr/= 3;
240  close_quote= FALSE;
241  break;
242  case INTERVAL_WEEK:
243  expr/= 7;
244  default:
245  close_quote= FALSE;
246  break;
247  }
248  if (close_quote)
249  buf->append(separator);
250  end= longlong10_to_str(expr, tmp_buff, 10);
251  buf->append(tmp_buff, (uint) (end- tmp_buff));
252  if (close_quote)
253  buf->append('\'');
254 
255  return 0;
256 }
257 
258 
271 static int
272 create_query_string(THD *thd, String *buf)
273 {
274  /* Append the "CREATE" part of the query */
275  if (buf->append(STRING_WITH_LEN("CREATE ")))
276  return 1;
277  /* Append definer */
278  append_definer(thd, buf, &(thd->lex->definer->user), &(thd->lex->definer->host));
279  /* Append the left part of thd->query after "DEFINER" part */
280  if (buf->append(thd->lex->stmt_definition_begin,
281  thd->lex->stmt_definition_end -
282  thd->lex->stmt_definition_begin))
283  return 1;
284 
285  return 0;
286 }
287 
288 
305 bool
307  bool if_not_exists)
308 {
309  bool ret;
310  bool save_binlog_row_based, event_already_exists;
311  DBUG_ENTER("Events::create_event");
312 
314  DBUG_RETURN(TRUE);
315 
316  /*
317  Perform semantic checks outside of Event_db_repository:
318  once CREATE EVENT is supported in prepared statements, the
319  checks will be moved to PREPARE phase.
320  */
321  if (parse_data->check_parse_data(thd))
322  DBUG_RETURN(TRUE);
323 
324  /* At create, one of them must be set */
325  DBUG_ASSERT(parse_data->expression || parse_data->execute_at);
326 
327  if (check_access(thd, EVENT_ACL, parse_data->dbname.str, NULL, NULL, 0, 0))
328  DBUG_RETURN(TRUE);
329 
330  if (check_db_dir_existence(parse_data->dbname.str))
331  {
332  my_error(ER_BAD_DB_ERROR, MYF(0), parse_data->dbname.str);
333  DBUG_RETURN(TRUE);
334  }
335 
336  if (parse_data->do_not_create)
337  DBUG_RETURN(FALSE);
338  /*
339  Turn off row binlogging of this statement and use statement-based
340  so that all supporting tables are updated for CREATE EVENT command.
341  */
342  if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
343  thd->clear_current_stmt_binlog_format_row();
344 
345  if (lock_object_name(thd, MDL_key::EVENT,
346  parse_data->dbname.str, parse_data->name.str))
347  DBUG_RETURN(TRUE);
348 
349  /* On error conditions my_error() is called so no need to handle here */
350  if (!(ret= db_repository->create_event(thd, parse_data, if_not_exists,
351  &event_already_exists)))
352  {
353  Event_queue_element *new_element;
354  bool dropped= 0;
355 
356  if (!event_already_exists)
357  {
358  if (!(new_element= new Event_queue_element()))
359  ret= TRUE; // OOM
360  else if ((ret= db_repository->load_named_event(thd, parse_data->dbname,
361  parse_data->name,
362  new_element)))
363  {
364  if (!db_repository->drop_event(thd, parse_data->dbname, parse_data->name,
365  TRUE))
366  dropped= 1;
367  delete new_element;
368  }
369  else
370  {
371  /* TODO: do not ignore the out parameter and a possible OOM error! */
372  bool created;
373  if (event_queue)
374  event_queue->create_event(thd, new_element, &created);
375  }
376  }
377  /*
378  binlog the create event unless it's been successfully dropped
379  */
380  if (!dropped)
381  {
382  /* Binlog the create event. */
383  DBUG_ASSERT(thd->query() && thd->query_length());
384  String log_query;
385  if (create_query_string(thd, &log_query))
386  {
387  sql_print_error("Event Error: An error occurred while creating query string, "
388  "before writing it into binary log.");
389  ret= true;
390  }
391  else
392  {
393  thd->add_to_binlog_accessed_dbs(parse_data->dbname.str);
394  /*
395  If the definer is not set or set to CURRENT_USER, the value of CURRENT_USER
396  will be written into the binary log as the definer for the SQL thread.
397  */
398  ret= write_bin_log(thd, TRUE, log_query.c_ptr(), log_query.length());
399  }
400  }
401  }
402  /* Restore the state of binlog format */
403  DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
404  if (save_binlog_row_based)
405  thd->set_current_stmt_binlog_format_row();
406 
407  DBUG_RETURN(ret);
408 }
409 
410 
430 bool
432  LEX_STRING *new_dbname, LEX_STRING *new_name)
433 {
434  int ret;
435  bool save_binlog_row_based;
436  Event_queue_element *new_element;
437 
438  DBUG_ENTER("Events::update_event");
439 
441  DBUG_RETURN(TRUE);
442 
443  if (parse_data->check_parse_data(thd) || parse_data->do_not_create)
444  DBUG_RETURN(TRUE);
445 
446  if (check_access(thd, EVENT_ACL, parse_data->dbname.str, NULL, NULL, 0, 0))
447  DBUG_RETURN(TRUE);
448 
449  if (new_dbname) /* It's a rename */
450  {
451  /* Check that the new and the old names differ. */
452  if ( !sortcmp_lex_string(parse_data->dbname, *new_dbname,
453  system_charset_info) &&
454  !sortcmp_lex_string(parse_data->name, *new_name,
455  system_charset_info))
456  {
457  my_error(ER_EVENT_SAME_NAME, MYF(0));
458  DBUG_RETURN(TRUE);
459  }
460 
461  /*
462  And the user has sufficient privileges to use the target database.
463  Do it before checking whether the database exists: we don't want
464  to tell the user that a database doesn't exist if they can not
465  access it.
466  */
467  if (check_access(thd, EVENT_ACL, new_dbname->str, NULL, NULL, 0, 0))
468  DBUG_RETURN(TRUE);
469 
470  /* Check that the target database exists */
471  if (check_db_dir_existence(new_dbname->str))
472  {
473  my_error(ER_BAD_DB_ERROR, MYF(0), new_dbname->str);
474  DBUG_RETURN(TRUE);
475  }
476  }
477 
478  /*
479  Turn off row binlogging of this statement and use statement-based
480  so that all supporting tables are updated for UPDATE EVENT command.
481  */
482  if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
483  thd->clear_current_stmt_binlog_format_row();
484 
485  if (lock_object_name(thd, MDL_key::EVENT,
486  parse_data->dbname.str, parse_data->name.str))
487  DBUG_RETURN(TRUE);
488 
489  /* On error conditions my_error() is called so no need to handle here */
490  if (!(ret= db_repository->update_event(thd, parse_data,
491  new_dbname, new_name)))
492  {
493  LEX_STRING dbname= new_dbname ? *new_dbname : parse_data->dbname;
494  LEX_STRING name= new_name ? *new_name : parse_data->name;
495 
496  if (!(new_element= new Event_queue_element()))
497  ret= TRUE; // OOM
498  else if ((ret= db_repository->load_named_event(thd, dbname, name,
499  new_element)))
500  delete new_element;
501  else
502  {
503  /*
504  TODO: check if an update actually has inserted an entry
505  into the queue.
506  If not, and the element is ON COMPLETION NOT PRESERVE, delete
507  it right away.
508  */
509  if (event_queue)
510  event_queue->update_event(thd, parse_data->dbname, parse_data->name,
511  new_element);
512  /* Binlog the alter event. */
513  DBUG_ASSERT(thd->query() && thd->query_length());
514 
515  thd->add_to_binlog_accessed_dbs(parse_data->dbname.str);
516  if (new_dbname)
517  thd->add_to_binlog_accessed_dbs(new_dbname->str);
518 
519  ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
520  }
521  }
522  /* Restore the state of binlog format */
523  DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
524  if (save_binlog_row_based)
525  thd->set_current_stmt_binlog_format_row();
526 
527  DBUG_RETURN(ret);
528 }
529 
530 
555 bool
556 Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists)
557 {
558  int ret;
559  bool save_binlog_row_based;
560  DBUG_ENTER("Events::drop_event");
561 
563  DBUG_RETURN(TRUE);
564 
565  if (check_access(thd, EVENT_ACL, dbname.str, NULL, NULL, 0, 0))
566  DBUG_RETURN(TRUE);
567 
568  /*
569  Turn off row binlogging of this statement and use statement-based so
570  that all supporting tables are updated for DROP EVENT command.
571  */
572  if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
573  thd->clear_current_stmt_binlog_format_row();
574 
575  if (lock_object_name(thd, MDL_key::EVENT,
576  dbname.str, name.str))
577  DBUG_RETURN(TRUE);
578  /* On error conditions my_error() is called so no need to handle here */
579  if (!(ret= db_repository->drop_event(thd, dbname, name, if_exists)))
580  {
581  if (event_queue)
582  event_queue->drop_event(thd, dbname, name);
583  /* Binlog the drop event. */
584  DBUG_ASSERT(thd->query() && thd->query_length());
585 
586  thd->add_to_binlog_accessed_dbs(dbname.str);
587  ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
588  }
589  /* Restore the state of binlog format */
590  DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
591  if (save_binlog_row_based)
592  thd->set_current_stmt_binlog_format_row();
593  DBUG_RETURN(ret);
594 }
595 
596 
608 void
609 Events::drop_schema_events(THD *thd, char *db)
610 {
611  LEX_STRING const db_lex= { db, strlen(db) };
612 
613  DBUG_ENTER("Events::drop_schema_events");
614  DBUG_PRINT("enter", ("dropping events from %s", db));
615 
616  /*
617  Sic: no check if the scheduler is disabled or system tables
618  are damaged, as intended.
619  */
620  if (event_queue)
621  event_queue->drop_schema_events(thd, db_lex);
622  db_repository->drop_schema_events(thd, db_lex);
623 
624  DBUG_VOID_RETURN;
625 }
626 
627 
633 static bool
634 send_show_create_event(THD *thd, Event_timed *et, Protocol *protocol)
635 {
636  char show_str_buf[10 * STRING_BUFFER_USUAL_SIZE];
637  String show_str(show_str_buf, sizeof(show_str_buf), system_charset_info);
638  List<Item> field_list;
639  LEX_STRING sql_mode;
640  const String *tz_name;
641 
642  DBUG_ENTER("send_show_create_event");
643 
644  show_str.length(0);
645  if (et->get_create_event(thd, &show_str))
646  DBUG_RETURN(TRUE);
647 
648  field_list.push_back(new Item_empty_string("Event", NAME_CHAR_LEN));
649 
650  if (sql_mode_string_representation(thd, et->sql_mode, &sql_mode))
651  DBUG_RETURN(TRUE);
652 
653  field_list.push_back(new Item_empty_string("sql_mode", (uint) sql_mode.length));
654 
655  tz_name= et->time_zone->get_name();
656 
657  field_list.push_back(new Item_empty_string("time_zone",
658  tz_name->length()));
659 
660  field_list.push_back(new Item_empty_string("Create Event",
661  show_str.length()));
662 
663  field_list.push_back(
664  new Item_empty_string("character_set_client", MY_CS_NAME_SIZE));
665 
666  field_list.push_back(
667  new Item_empty_string("collation_connection", MY_CS_NAME_SIZE));
668 
669  field_list.push_back(
670  new Item_empty_string("Database Collation", MY_CS_NAME_SIZE));
671 
672  if (protocol->send_result_set_metadata(&field_list,
673  Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
674  DBUG_RETURN(TRUE);
675 
676  protocol->prepare_for_resend();
677 
678  protocol->store(et->name.str, et->name.length, system_charset_info);
679  protocol->store(sql_mode.str, sql_mode.length, system_charset_info);
680  protocol->store(tz_name->ptr(), tz_name->length(), system_charset_info);
681  protocol->store(show_str.c_ptr(), show_str.length(),
682  et->creation_ctx->get_client_cs());
683  protocol->store(et->creation_ctx->get_client_cs()->csname,
684  strlen(et->creation_ctx->get_client_cs()->csname),
685  system_charset_info);
686  protocol->store(et->creation_ctx->get_connection_cl()->name,
687  strlen(et->creation_ctx->get_connection_cl()->name),
688  system_charset_info);
689  protocol->store(et->creation_ctx->get_db_cl()->name,
690  strlen(et->creation_ctx->get_db_cl()->name),
691  system_charset_info);
692 
693  if (protocol->write())
694  DBUG_RETURN(TRUE);
695 
696  my_eof(thd);
697 
698  DBUG_RETURN(FALSE);
699 }
700 
701 
712 bool
714 {
715  Event_timed et;
716  bool ret;
717 
718  DBUG_ENTER("Events::show_create_event");
719  DBUG_PRINT("enter", ("name: %s@%s", dbname.str, name.str));
720 
722  DBUG_RETURN(TRUE);
723 
724  if (check_access(thd, EVENT_ACL, dbname.str, NULL, NULL, 0, 0))
725  DBUG_RETURN(TRUE);
726 
727  /*
728  We would like to allow SHOW CREATE EVENT under LOCK TABLES and
729  in pre-locked mode. mysql.event table is marked as a system table.
730  This flag reduces the set of its participation scenarios in LOCK TABLES
731  operation, and therefore an out-of-bound open of this table
732  for reading like the one below (sic, only for reading) is
733  more or less deadlock-free. For additional information about when a
734  deadlock can occur please refer to the description of 'system table'
735  flag.
736  */
737  ret= db_repository->load_named_event(thd, dbname, name, &et);
738 
739  if (!ret)
740  ret= send_show_create_event(thd, &et, thd->protocol);
741 
742  DBUG_RETURN(ret);
743 }
744 
745 
762 int
763 Events::fill_schema_events(THD *thd, TABLE_LIST *tables, Item * /* cond */)
764 {
765  char *db= NULL;
766  int ret;
767  DBUG_ENTER("Events::fill_schema_events");
768 
770  DBUG_RETURN(1);
771 
772  /*
773  If it's SHOW EVENTS then thd->lex->select_lex.db is guaranteed not to
774  be NULL. Let's do an assert anyway.
775  */
776  if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS)
777  {
778  DBUG_ASSERT(thd->lex->select_lex.db);
779  if (!is_infoschema_db(thd->lex->select_lex.db) && // There is no events in I_S
780  check_access(thd, EVENT_ACL, thd->lex->select_lex.db,
781  NULL, NULL, 0, 0))
782  DBUG_RETURN(1);
783  db= thd->lex->select_lex.db;
784  }
785  ret= db_repository->fill_schema_events(thd, tables, db);
786 
787  DBUG_RETURN(ret);
788 }
789 
790 
806 bool
807 Events::init(my_bool opt_noacl_or_bootstrap)
808 {
809 
810  THD *thd;
811  int err_no;
812  bool res= FALSE;
813 
814  DBUG_ENTER("Events::init");
815 
816  /* We need a temporary THD during boot */
817  if (!(thd= new THD()))
818  {
819  res= TRUE;
820  goto end;
821  }
822  /*
823  The thread stack does not start from this function but we cannot
824  guess the real value. So better some value that doesn't assert than
825  no value.
826  */
827  thd->thread_stack= (char*) &thd;
828  thd->store_globals();
829  /*
830  Set current time for the thread that handles events.
831  Current time is stored in data member start_time of THD class.
832  Subsequently, this value is used to check whether event was expired
833  when make loading events from storage. Check for event expiration time
834  is done at Event_queue_element::compute_next_execution_time() where
835  event's status set to Event_parse_data::DISABLED and dropped flag set
836  to true if event was expired.
837  */
838  thd->set_time();
839  /*
840  We will need Event_db_repository anyway, even if the scheduler is
841  disabled - to perform events DDL.
842  */
843  if (!(db_repository= new Event_db_repository))
844  {
845  res= TRUE; /* fatal error: request unireg_abort */
846  goto end;
847  }
848 
849  /*
850  Since we allow event DDL even if the scheduler is disabled,
851  check the system tables, as we might need them.
852 
853  If run with --skip-grant-tables or --bootstrap, don't try to do the
854  check of system tables and don't complain: in these modes the tables
855  are most likely not there and we're going to disable the event
856  scheduler anyway.
857  */
858  if (opt_noacl_or_bootstrap || Event_db_repository::check_system_tables(thd))
859  {
860  if (! opt_noacl_or_bootstrap)
861  {
862  sql_print_error("Event Scheduler: An error occurred when initializing "
863  "system tables. Disabling the Event Scheduler.");
864  check_system_tables_error= TRUE;
865  }
866 
867  /* Disable the scheduler since the system tables are not up to date */
868  opt_event_scheduler= EVENTS_DISABLED;
869  goto end;
870  }
871 
872  /*
873  Was disabled explicitly from the command line, or because we're running
874  with --skip-grant-tables, or --bootstrap, or because we have no system
875  tables.
876  */
877  if (opt_event_scheduler == Events::EVENTS_DISABLED)
878  goto end;
879 
880 
881  DBUG_ASSERT(opt_event_scheduler == Events::EVENTS_ON ||
882  opt_event_scheduler == Events::EVENTS_OFF);
883 
884  if (!(event_queue= new Event_queue) ||
885  !(scheduler= new Event_scheduler(event_queue)))
886  {
887  res= TRUE; /* fatal error: request unireg_abort */
888  goto end;
889  }
890 
891  if (event_queue->init_queue(thd) || load_events_from_db(thd) ||
892  (opt_event_scheduler == EVENTS_ON && scheduler->start(&err_no)))
893  {
894  sql_print_error("Event Scheduler: Error while loading from disk.");
895  res= TRUE; /* fatal error: request unireg_abort */
896  goto end;
897  }
898  Event_worker_thread::init(db_repository);
899 
900 end:
901  if (res)
902  {
903  delete db_repository;
904  delete event_queue;
905  delete scheduler;
906  }
907  delete thd;
908  /* Remember that we don't have a THD */
909  my_pthread_setspecific_ptr(THR_THD, NULL);
910 
911  DBUG_RETURN(res);
912 }
913 
914 /*
915  Cleans up scheduler's resources. Called at server shutdown.
916 
917  SYNOPSIS
918  Events::deinit()
919 
920  NOTES
921  This function is not synchronized.
922 */
923 
924 void
925 Events::deinit()
926 {
927  DBUG_ENTER("Events::deinit");
928 
929  if (opt_event_scheduler != EVENTS_DISABLED)
930  {
931  delete scheduler;
932  scheduler= NULL; /* safety */
933  delete event_queue;
934  event_queue= NULL; /* safety */
935  }
936 
937  delete db_repository;
938  db_repository= NULL; /* safety */
939 
940  DBUG_VOID_RETURN;
941 }
942 
943 #ifdef HAVE_PSI_INTERFACE
944 PSI_mutex_key key_LOCK_event_queue,
945  key_event_scheduler_LOCK_scheduler_state;
946 
947 static PSI_mutex_info all_events_mutexes[]=
948 {
949  { &key_LOCK_event_queue, "LOCK_event_queue", PSI_FLAG_GLOBAL},
950  { &key_event_scheduler_LOCK_scheduler_state, "Event_scheduler::LOCK_scheduler_state", PSI_FLAG_GLOBAL}
951 };
952 
953 PSI_cond_key key_event_scheduler_COND_state, key_COND_queue_state;
954 
955 static PSI_cond_info all_events_conds[]=
956 {
957  { &key_event_scheduler_COND_state, "Event_scheduler::COND_state", PSI_FLAG_GLOBAL},
958  { &key_COND_queue_state, "COND_queue_state", PSI_FLAG_GLOBAL},
959 };
960 
961 PSI_thread_key key_thread_event_scheduler, key_thread_event_worker;
962 
963 static PSI_thread_info all_events_threads[]=
964 {
965  { &key_thread_event_scheduler, "event_scheduler", PSI_FLAG_GLOBAL},
966  { &key_thread_event_worker, "event_worker", 0}
967 };
968 #endif /* HAVE_PSI_INTERFACE */
969 
970 PSI_stage_info stage_waiting_on_empty_queue= { 0, "Waiting on empty queue", 0};
971 PSI_stage_info stage_waiting_for_next_activation= { 0, "Waiting for next activation", 0};
972 PSI_stage_info stage_waiting_for_scheduler_to_stop= { 0, "Waiting for the scheduler to stop", 0};
973 
974 #ifdef HAVE_PSI_INTERFACE
975 PSI_stage_info *all_events_stages[]=
976 {
977  & stage_waiting_on_empty_queue,
978  & stage_waiting_for_next_activation,
979  & stage_waiting_for_scheduler_to_stop
980 };
981 
982 static void init_events_psi_keys(void)
983 {
984  const char* category= "sql";
985  int count;
986 
987  count= array_elements(all_events_mutexes);
988  mysql_mutex_register(category, all_events_mutexes, count);
989 
990  count= array_elements(all_events_conds);
991  mysql_cond_register(category, all_events_conds, count);
992 
993  count= array_elements(all_events_threads);
994  mysql_thread_register(category, all_events_threads, count);
995 
996  count= array_elements(all_events_stages);
997  mysql_stage_register(category, all_events_stages, count);
998 
999 }
1000 #endif /* HAVE_PSI_INTERFACE */
1001 
1010 void
1012 {
1013 #ifdef HAVE_PSI_INTERFACE
1014  init_events_psi_keys();
1015 #endif
1016 }
1017 
1018 
1019 /*
1020  Dumps the internal status of the scheduler and the memory cache
1021  into a table with two columns - Name & Value. Different properties
1022  which could be useful for debugging for instance deadlocks are
1023  returned.
1024 
1025  SYNOPSIS
1026  Events::dump_internal_status()
1027 */
1028 
1029 void
1030 Events::dump_internal_status()
1031 {
1032  DBUG_ENTER("Events::dump_internal_status");
1033  puts("\n\n\nEvents status:");
1034  puts("LLA = Last Locked At LUA = Last Unlocked At");
1035  puts("WOC = Waiting On Condition DL = Data Locked");
1036 
1037  /*
1038  opt_event_scheduler should only be accessed while
1039  holding LOCK_global_system_variables.
1040  */
1041  mysql_mutex_lock(&LOCK_global_system_variables);
1042  if (opt_event_scheduler == EVENTS_DISABLED)
1043  puts("The Event Scheduler is disabled");
1044  else
1045  {
1046  scheduler->dump_internal_status();
1047  event_queue->dump_internal_status();
1048  }
1049 
1050  mysql_mutex_unlock(&LOCK_global_system_variables);
1051  DBUG_VOID_RETURN;
1052 }
1053 
1054 bool Events::start(int *err_no)
1055 {
1056  return scheduler->start(err_no);
1057 }
1058 
1059 bool Events::stop()
1060 {
1061  return scheduler->stop();
1062 }
1063 
1082 bool
1083 Events::load_events_from_db(THD *thd)
1084 {
1085  TABLE *table;
1086  READ_RECORD read_record_info;
1087  bool ret= TRUE;
1088  uint count= 0;
1089  ulong saved_master_access;
1090 
1091  DBUG_ENTER("Events::load_events_from_db");
1092  DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
1093 
1094  /*
1095  NOTE: even if we run in read-only mode, we should be able to lock the
1096  mysql.event table for writing. In order to achieve this, we should call
1097  mysql_lock_tables() under the super user.
1098 
1099  Same goes for transaction access mode.
1100  Temporarily reset it to read-write.
1101  */
1102 
1103  saved_master_access= thd->security_ctx->master_access;
1104  thd->security_ctx->master_access |= SUPER_ACL;
1105  bool save_tx_read_only= thd->tx_read_only;
1106  thd->tx_read_only= false;
1107 
1108  ret= db_repository->open_event_table(thd, TL_WRITE, &table);
1109 
1110  thd->tx_read_only= save_tx_read_only;
1111  thd->security_ctx->master_access= saved_master_access;
1112 
1113  if (ret)
1114  {
1115  sql_print_error("Event Scheduler: Failed to open table mysql.event");
1116  DBUG_RETURN(TRUE);
1117  }
1118 
1119  if (init_read_record(&read_record_info, thd, table, NULL, 0, 1, FALSE))
1120  {
1121  sql_print_error("Event Scheduler: Error while starting read of mysql.event");
1122  DBUG_RETURN(TRUE);
1123  }
1124  while (!(read_record_info.read_record(&read_record_info)))
1125  {
1126  Event_queue_element *et;
1127  bool created, dropped;
1128 
1129  if (!(et= new Event_queue_element))
1130  goto end;
1131 
1132  DBUG_PRINT("info", ("Loading event from row."));
1133 
1134  if (et->load_from_row(thd, table))
1135  {
1136  sql_print_error("Event Scheduler: "
1137  "Error while loading events from mysql.event. "
1138  "The table probably contains bad data or is corrupted");
1139  delete et;
1140  goto end;
1141  }
1142 
1148  dropped= et->dropped;
1149  if (event_queue->create_event(thd, et, &created))
1150  {
1151  /* Out of memory */
1152  delete et;
1153  goto end;
1154  }
1155  if (created)
1156  count++;
1157  else if (dropped)
1158  {
1159  /*
1160  If not created, a stale event - drop if immediately if
1161  ON COMPLETION NOT PRESERVE.
1162  XXX: This won't be replicated, thus the drop won't appear in
1163  in the slave. When the slave is restarted it will drop events.
1164  However, as the slave will be "out of sync", it might happen that
1165  an event created on the master, after master restart, won't be
1166  replicated to the slave correctly, as the create will fail there.
1167  */
1168  int rc= table->file->ha_delete_row(table->record[0]);
1169  if (rc)
1170  {
1171  table->file->print_error(rc, MYF(0));
1172  goto end;
1173  }
1174  }
1175  }
1176  sql_print_information("Event Scheduler: Loaded %d event%s",
1177  count, (count == 1) ? "" : "s");
1178  ret= FALSE;
1179 
1180 end:
1181  end_read_record(&read_record_info);
1182 
1183  close_mysql_tables(thd);
1184  DBUG_RETURN(ret);
1185 }
1186