1 /*
2    Copyright (c) 2005, 2021, Oracle and/or its affiliates.
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, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA */
23 
24 #include "events.h"
25 
26 #include "sql_parse.h"                          // check_access
27 #include "sql_base.h"                           // close_mysql_tables
28 #include "sql_show.h"                           // append_definer
29 #include "sql_db.h"                          // check_db_dir_existence
30 #include "sql_table.h"                       // write_bin_log
31 #include "tztime.h"                             // struct Time_zone
32 #include "auth_common.h"                        // EVENT_ACL
33 #include "records.h"          // init_read_record, end_read_record
34 #include "event_data_objects.h"
35 #include "event_db_repository.h"
36 #include "event_queue.h"
37 #include "event_scheduler.h"
38 #include "sp_head.h" // for Stored_program_creation_ctx
39 #include "lock.h"   // lock_object_name
40 #include "log.h"
41 #include "mysql/psi/mysql_sp.h"
42 #include "debug_sync.h"
43 
44 /**
45   @addtogroup Event_Scheduler
46   @{
47 */
48 
49 /*
50  TODO list :
51  - CREATE EVENT should not go into binary log! Does it now? The SQL statements
52    issued by the EVENT are replicated.
53    I have an idea how to solve the problem at failover. So the status field
54    will be ENUM('DISABLED', 'ENABLED', 'SLAVESIDE_DISABLED').
55    In this case when CREATE EVENT is replicated it should go into the binary
56    as SLAVESIDE_DISABLED if it is ENABLED, when it's created as DISABLEd it
57    should be replicated as disabled. If an event is ALTERed as DISABLED the
58    query should go untouched into the binary log, when ALTERed as enable then
59    it should go as SLAVESIDE_DISABLED. This is regarding the SQL interface.
60    TT routines however modify mysql.event internally and this does not go the
61    log so in this case queries has to be injected into the log...somehow... or
62    maybe a solution is RBR for this case, because the event may go only from
63    ENABLED to DISABLED status change and this is safe for replicating. As well
64    an event may be deleted which is also safe for RBR.
65 
66  - Add logging to file
67 
68 */
69 
70 
71 /*
72   If the user (un)intentionally removes an event directly from mysql.event
73   the following sequence has to be used to be able to remove the in-memory
74   counterpart.
75   1. CREATE EVENT the_name ON SCHEDULE EVERY 1 SECOND DISABLE DO SELECT 1;
76   2. DROP EVENT the_name
77 
78   In other words, the first one will create a row in mysql.event . In the
79   second step because there will be a line, disk based drop will pass and
80   the scheduler will remove the memory counterpart. The reason is that
81   in-memory queue does not check whether the event we try to drop from memory
82   is disabled. Disabled events are not kept in-memory because they are not
83   eligible for execution.
84 */
85 
86 Event_queue *Events::event_queue;
87 Event_scheduler *Events::scheduler;
88 Event_db_repository *Events::db_repository;
89 ulong Events::opt_event_scheduler= Events::EVENTS_OFF;
90 bool Events::check_system_tables_error= FALSE;
91 
92 
93 /*
94   Compares 2 LEX strings regarding case.
95 
96   SYNOPSIS
97     sortcmp_lex_string()
98       s   First LEX_STRING
99       t   Second LEX_STRING
100       cs  Charset
101 
102   RETURN VALUE
103    -1   s < t
104     0   s == t
105     1   s > t
106 */
107 
sortcmp_lex_string(LEX_STRING s,LEX_STRING t,CHARSET_INFO * cs)108 int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
109 {
110  return cs->coll->strnncollsp(cs, (uchar *) s.str,s.length,
111                                   (uchar *) t.str,t.length, 0);
112 }
113 
114 
115 /**
116   Push an error into the error stack if the system tables are
117   not up to date.
118 */
119 
check_if_system_tables_error()120 bool Events::check_if_system_tables_error()
121 {
122   DBUG_ENTER("Events::check_if_system_tables_error");
123 
124   if (check_system_tables_error)
125   {
126     my_error(ER_EVENTS_DB_ERROR, MYF(0));
127     DBUG_RETURN(TRUE);
128   }
129 
130   DBUG_RETURN(FALSE);
131 }
132 
133 
134 /**
135   Reconstructs interval expression from interval type and expression
136   value that is in form of a value of the smalles entity:
137   For
138     YEAR_MONTH - expression is in months
139     DAY_MINUTE - expression is in minutes
140 
141   SYNOPSIS
142     Events::reconstruct_interval_expression()
143       buf         Preallocated String buffer to add the value to
144       interval    The interval type (for instance YEAR_MONTH)
145       expression  The value in the lowest entity
146 
147   RETURN VALUE
148     0  OK
149     1  Error
150 */
151 
152 int
reconstruct_interval_expression(String * buf,interval_type interval,longlong expression)153 Events::reconstruct_interval_expression(String *buf, interval_type interval,
154                                         longlong expression)
155 {
156   ulonglong expr= expression;
157   char tmp_buff[128], *end;
158   bool close_quote= TRUE;
159   int multipl= 0;
160   char separator=':';
161 
162   switch (interval) {
163   case INTERVAL_YEAR_MONTH:
164     multipl= 12;
165     separator= '-';
166     goto common_1_lev_code;
167   case INTERVAL_DAY_HOUR:
168     multipl= 24;
169     separator= ' ';
170     goto common_1_lev_code;
171   case INTERVAL_HOUR_MINUTE:
172   case INTERVAL_MINUTE_SECOND:
173     multipl= 60;
174 common_1_lev_code:
175     buf->append('\'');
176     end= longlong10_to_str(expression/multipl, tmp_buff, 10);
177     buf->append(tmp_buff, (uint) (end- tmp_buff));
178     expr= expr - (expr/multipl)*multipl;
179     break;
180   case INTERVAL_DAY_MINUTE:
181   {
182     ulonglong tmp_expr= expr;
183 
184     tmp_expr/=(24*60);
185     buf->append('\'');
186     end= longlong10_to_str(tmp_expr, tmp_buff, 10);
187     buf->append(tmp_buff, (uint) (end- tmp_buff));// days
188     buf->append(' ');
189 
190     tmp_expr= expr - tmp_expr*(24*60);//minutes left
191     end= longlong10_to_str(tmp_expr/60, tmp_buff, 10);
192     buf->append(tmp_buff, (uint) (end- tmp_buff));// hours
193 
194     expr= tmp_expr - (tmp_expr/60)*60;
195     /* the code after the switch will finish */
196   }
197     break;
198   case INTERVAL_HOUR_SECOND:
199   {
200     ulonglong tmp_expr= expr;
201 
202     buf->append('\'');
203     end= longlong10_to_str(tmp_expr/3600, tmp_buff, 10);
204     buf->append(tmp_buff, (uint) (end- tmp_buff));// hours
205     buf->append(':');
206 
207     tmp_expr= tmp_expr - (tmp_expr/3600)*3600;
208     end= longlong10_to_str(tmp_expr/60, tmp_buff, 10);
209     buf->append(tmp_buff, (uint) (end- tmp_buff));// minutes
210 
211     expr= tmp_expr - (tmp_expr/60)*60;
212     /* the code after the switch will finish */
213   }
214     break;
215   case INTERVAL_DAY_SECOND:
216   {
217     ulonglong tmp_expr= expr;
218 
219     tmp_expr/=(24*3600);
220     buf->append('\'');
221     end= longlong10_to_str(tmp_expr, tmp_buff, 10);
222     buf->append(tmp_buff, (uint) (end- tmp_buff));// days
223     buf->append(' ');
224 
225     tmp_expr= expr - tmp_expr*(24*3600);//seconds left
226     end= longlong10_to_str(tmp_expr/3600, tmp_buff, 10);
227     buf->append(tmp_buff, (uint) (end- tmp_buff));// hours
228     buf->append(':');
229 
230     tmp_expr= tmp_expr - (tmp_expr/3600)*3600;
231     end= longlong10_to_str(tmp_expr/60, tmp_buff, 10);
232     buf->append(tmp_buff, (uint) (end- tmp_buff));// minutes
233 
234     expr= tmp_expr - (tmp_expr/60)*60;
235     /* the code after the switch will finish */
236   }
237     break;
238   case INTERVAL_DAY_MICROSECOND:
239   case INTERVAL_HOUR_MICROSECOND:
240   case INTERVAL_MINUTE_MICROSECOND:
241   case INTERVAL_SECOND_MICROSECOND:
242   case INTERVAL_MICROSECOND:
243     my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND");
244     return 1;
245     break;
246   case INTERVAL_QUARTER:
247     expr/= 3;
248     close_quote= FALSE;
249     break;
250   case INTERVAL_WEEK:
251     expr/= 7;
252     close_quote= FALSE;
253     break;
254   default:
255     close_quote= FALSE;
256     break;
257   }
258   if (close_quote)
259     buf->append(separator);
260   end= longlong10_to_str(expr, tmp_buff, 10);
261   buf->append(tmp_buff, (uint) (end- tmp_buff));
262   if (close_quote)
263     buf->append('\'');
264 
265   return 0;
266 }
267 
268 
269 /**
270   Create a new query string for removing executable comments
271   for avoiding leak and keeping consistency of the execution
272   on master and slave.
273 
274   @param[in] thd                 Thread handler
275   @param[in] buf                 Query string
276 
277   @return
278              0           ok
279              1           error
280 */
281 static int
create_query_string(THD * thd,String * buf)282 create_query_string(THD *thd, String *buf)
283 {
284   /* Append the "CREATE" part of the query */
285   if (buf->append(STRING_WITH_LEN("CREATE ")))
286     return 1;
287   /* Append definer */
288   append_definer(thd, buf, thd->lex->definer->user, thd->lex->definer->host);
289   /* Append the left part of thd->query after "DEFINER" part */
290   if (buf->append(thd->lex->stmt_definition_begin,
291                   thd->lex->stmt_definition_end -
292                   thd->lex->stmt_definition_begin))
293     return 1;
294 
295   return 0;
296 }
297 
298 
299 /**
300   Create a new event.
301 
302   @param[in,out]  thd            THD
303   @param[in]      parse_data     Event's data from parsing stage
304   @param[in]      if_not_exists  Whether IF NOT EXISTS was
305                                  specified
306   In case there is an event with the same name (db) and
307   IF NOT EXISTS is specified, an warning is put into the stack.
308   @sa Events::drop_event for the notes about locking, pre-locking
309   and Events DDL.
310 
311   @retval  FALSE  OK
312   @retval  TRUE   Error (reported)
313 */
314 
315 bool
create_event(THD * thd,Event_parse_data * parse_data,bool if_not_exists)316 Events::create_event(THD *thd, Event_parse_data *parse_data,
317                      bool if_not_exists)
318 {
319   bool ret;
320   bool save_binlog_row_based, event_already_exists;
321   ulong save_binlog_format= thd->variables.binlog_format;
322   DBUG_ENTER("Events::create_event");
323 
324   if (check_if_system_tables_error())
325     DBUG_RETURN(TRUE);
326 
327   /*
328     Perform semantic checks outside of Event_db_repository:
329     once CREATE EVENT is supported in prepared statements, the
330     checks will be moved to PREPARE phase.
331   */
332   if (parse_data->check_parse_data(thd))
333     DBUG_RETURN(TRUE);
334 
335   /* At create, one of them must be set */
336   assert(parse_data->expression || parse_data->execute_at);
337 
338   if (check_access(thd, EVENT_ACL, parse_data->dbname.str, NULL, NULL, 0, 0))
339     DBUG_RETURN(TRUE);
340 
341   if (lock_object_name(thd, MDL_key::EVENT,
342                        parse_data->dbname.str, parse_data->name.str))
343     DBUG_RETURN(TRUE);
344 
345   if (check_db_dir_existence(parse_data->dbname.str))
346   {
347     my_error(ER_BAD_DB_ERROR, MYF(0), parse_data->dbname.str);
348     DBUG_RETURN(TRUE);
349   }
350 
351   if (parse_data->do_not_create)
352     DBUG_RETURN(FALSE);
353   /*
354     Turn off row binlogging of this statement and use statement-based
355     so that all supporting tables are updated for CREATE EVENT command.
356   */
357   if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
358     thd->clear_current_stmt_binlog_format_row();
359   thd->variables.binlog_format= BINLOG_FORMAT_STMT;
360 
361   /* On error conditions my_error() is called so no need to handle here */
362   if (!(ret= db_repository->create_event(thd, parse_data, if_not_exists,
363                                          &event_already_exists)))
364   {
365     Event_queue_element *new_element;
366     bool dropped= 0;
367 
368     if (opt_event_scheduler != Events::EVENTS_DISABLED && !event_already_exists)
369     {
370       if (!(new_element= new Event_queue_element()))
371         ret= TRUE;                                // OOM
372       else if ((ret= db_repository->load_named_event(thd, parse_data->dbname,
373                                                      parse_data->name,
374                                                      new_element)))
375       {
376         if (!db_repository->drop_event(thd, parse_data->dbname, parse_data->name,
377                                        TRUE))
378           dropped= 1;
379         delete new_element;
380       }
381       else
382       {
383         /* TODO: do not ignore the out parameter and a possible OOM error! */
384         bool created;
385         if (event_queue)
386           event_queue->create_event(thd, new_element, &created);
387       }
388     }
389     /*
390       binlog the create event unless it's been successfully dropped
391     */
392     if (!dropped)
393     {
394       /* Binlog the create event. */
395       assert(thd->query().str && thd->query().length);
396       String log_query;
397       if (create_query_string(thd, &log_query))
398       {
399         sql_print_error("Event Error: An error occurred while creating query string, "
400                         "before writing it into binary log.");
401         ret= true;
402       }
403       else
404       {
405         thd->add_to_binlog_accessed_dbs(parse_data->dbname.str);
406         /*
407           If the definer is not set or set to CURRENT_USER, the value of CURRENT_USER
408           will be written into the binary log as the definer for the SQL thread.
409         */
410         ret= write_bin_log(thd, TRUE, log_query.c_ptr(), log_query.length());
411       }
412     }
413   }
414   /* Restore the state of binlog format */
415   assert(!thd->is_current_stmt_binlog_format_row());
416   if (save_binlog_row_based)
417     thd->set_current_stmt_binlog_format_row();
418   thd->variables.binlog_format= save_binlog_format;
419 
420   DBUG_RETURN(ret);
421 }
422 
423 
424 /**
425   Alter an event.
426 
427   @param[in,out] thd         THD
428   @param[in]     parse_data  Event's data from parsing stage
429   @param[in]     new_dbname  A new schema name for the event. Set in the case of
430                              ALTER EVENT RENAME, otherwise is NULL.
431   @param[in]     new_name    A new name for the event. Set in the case of
432                              ALTER EVENT RENAME
433 
434   Parameter 'et' contains data about dbname and event name.
435   Parameter 'new_name' is the new name of the event, if not null
436   this means that RENAME TO was specified in the query
437   @sa Events::drop_event for the locking notes.
438 
439   @retval  FALSE  OK
440   @retval  TRUE   error (reported)
441 */
442 
443 bool
update_event(THD * thd,Event_parse_data * parse_data,LEX_STRING * new_dbname,LEX_STRING * new_name)444 Events::update_event(THD *thd, Event_parse_data *parse_data,
445                      LEX_STRING *new_dbname, LEX_STRING *new_name)
446 {
447   int ret;
448   bool save_binlog_row_based;
449   ulong save_binlog_format= thd->variables.binlog_format;
450   Event_queue_element *new_element;
451 
452   DBUG_ENTER("Events::update_event");
453 
454   if (check_if_system_tables_error())
455     DBUG_RETURN(TRUE);
456 
457   if (parse_data->check_parse_data(thd) || parse_data->do_not_create)
458     DBUG_RETURN(TRUE);
459 
460   if (check_access(thd, EVENT_ACL, parse_data->dbname.str, NULL, NULL, 0, 0))
461     DBUG_RETURN(TRUE);
462 
463   if (lock_object_name(thd, MDL_key::EVENT,
464                        parse_data->dbname.str, parse_data->name.str))
465     DBUG_RETURN(TRUE);
466 
467   if (check_db_dir_existence(parse_data->dbname.str))
468   {
469     my_error(ER_BAD_DB_ERROR, MYF(0), parse_data->dbname.str);
470     DBUG_RETURN(TRUE);
471   }
472 
473   if (new_dbname != NULL)                               /* It's a rename */
474   {
475     /* Check that the new and the old names differ. */
476     if ( !sortcmp_lex_string(parse_data->dbname, *new_dbname,
477                              system_charset_info) &&
478          !sortcmp_lex_string(parse_data->name, *new_name,
479                              system_charset_info))
480     {
481       my_error(ER_EVENT_SAME_NAME, MYF(0));
482       DBUG_RETURN(TRUE);
483     }
484 
485     /*
486       And the user has sufficient privileges to use the target database.
487       Do it before checking whether the database exists: we don't want
488       to tell the user that a database doesn't exist if they can not
489       access it.
490     */
491     if (check_access(thd, EVENT_ACL, new_dbname->str, NULL, NULL, 0, 0))
492       DBUG_RETURN(TRUE);
493 
494     /*
495       Acquire mdl exclusive lock on target database name.
496     */
497     if (lock_object_name(thd, MDL_key::EVENT,
498                          new_dbname->str, new_name->str))
499       DBUG_RETURN(TRUE);
500 
501     /* Check that the target database exists */
502     if (check_db_dir_existence(new_dbname->str))
503     {
504       my_error(ER_BAD_DB_ERROR, MYF(0), new_dbname->str);
505       DBUG_RETURN(TRUE);
506     }
507   }
508 
509   /*
510     Turn off row binlogging of this statement and use statement-based
511     so that all supporting tables are updated for UPDATE EVENT command.
512   */
513   if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
514     thd->clear_current_stmt_binlog_format_row();
515   thd->variables.binlog_format= BINLOG_FORMAT_STMT;
516 
517   /* On error conditions my_error() is called so no need to handle here */
518   if (!(ret= db_repository->update_event(thd, parse_data,
519                                          new_dbname, new_name)))
520   {
521     LEX_STRING dbname= new_dbname ? *new_dbname : parse_data->dbname;
522     LEX_STRING name= new_name ? *new_name : parse_data->name;
523 
524     DEBUG_SYNC(thd, "after_alter_event_updated_event_table");
525 
526     if (opt_event_scheduler != Events::EVENTS_DISABLED)
527     {
528       if (!(new_element= new Event_queue_element()))
529         ret= TRUE;                                // OOM
530       else if ((ret= db_repository->load_named_event(thd, dbname, name,
531                                                    new_element)))
532         delete new_element;
533       else
534       {
535         /*
536           TODO: check if an update actually has inserted an entry
537           into the queue.
538           If not, and the element is ON COMPLETION NOT PRESERVE, delete
539           it right away.
540         */
541         if (event_queue)
542           event_queue->update_event(thd, parse_data->dbname, parse_data->name,
543                                     new_element);
544       }
545     }
546 
547     /* Binlog the alter event. */
548     assert(thd->query().str && thd->query().length);
549 
550     thd->add_to_binlog_accessed_dbs(parse_data->dbname.str);
551     if (new_dbname)
552       thd->add_to_binlog_accessed_dbs(new_dbname->str);
553 
554     ret|= write_bin_log(thd, true, thd->query().str, thd->query().length);
555   }
556   /* Restore the state of binlog format */
557   assert(!thd->is_current_stmt_binlog_format_row());
558   if (save_binlog_row_based)
559     thd->set_current_stmt_binlog_format_row();
560   thd->variables.binlog_format= save_binlog_format;
561 
562   DBUG_RETURN(ret);
563 }
564 
565 
566 /**
567   Drops an event
568 
569   @param[in,out]  thd        THD
570   @param[in]      dbname     Event's schema
571   @param[in]      name       Event's name
572   @param[in]      if_exists  When this is set and the event does not exist
573                              a warning is pushed into the warning stack.
574                              Otherwise the operation produces an error.
575 
576   @note Similarly to DROP PROCEDURE, we do not allow DROP EVENT
577   under LOCK TABLES mode, unless table mysql.event is locked.  To
578   ensure that, we do not reset & backup the open tables state in
579   this function - if in LOCK TABLES or pre-locking mode, this will
580   lead to an error 'Table mysql.event is not locked with LOCK
581   TABLES' unless it _is_ locked. In pre-locked mode there is
582   another barrier - DROP EVENT commits the current transaction,
583   and COMMIT/ROLLBACK is not allowed in stored functions and
584   triggers.
585 
586   @retval  FALSE  OK
587   @retval  TRUE   Error (reported)
588 */
589 
590 bool
drop_event(THD * thd,LEX_STRING dbname,LEX_STRING name,bool if_exists)591 Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists)
592 {
593   int ret;
594   DBUG_ENTER("Events::drop_event");
595 
596   if (check_if_system_tables_error())
597     DBUG_RETURN(TRUE);
598 
599   if (check_access(thd, EVENT_ACL, dbname.str, NULL, NULL, 0, 0))
600     DBUG_RETURN(TRUE);
601 
602   if (lock_object_name(thd, MDL_key::EVENT,
603                        dbname.str, name.str))
604     DBUG_RETURN(TRUE);
605   /* On error conditions my_error() is called so no need to handle here */
606   if (!(ret= db_repository->drop_event(thd, dbname, name, if_exists)))
607   {
608     if (event_queue)
609       event_queue->drop_event(thd, dbname, name);
610     /* Binlog the drop event. */
611     assert(thd->query().str && thd->query().length);
612 
613     thd->add_to_binlog_accessed_dbs(dbname.str);
614     ret= write_bin_log(thd, TRUE, thd->query().str, thd->query().length);
615 #ifdef HAVE_PSI_SP_INTERFACE
616     /* Drop statistics for this stored program from performance schema. */
617     MYSQL_DROP_SP(SP_TYPE_EVENT,
618                   dbname.str, dbname.length, name.str, name.length);
619 #endif
620   }
621   DBUG_RETURN(ret);
622 }
623 
624 
625 /**
626   Drops all events from a schema
627 
628   @note We allow to drop all events in a schema even if the
629   scheduler is disabled. This is to not produce any warnings
630   in case of DROP DATABASE and a disabled scheduler.
631 
632   @param[in,out]  thd  Thread
633   @param[in]      db   ASCIIZ schema name
634 */
635 
636 void
drop_schema_events(THD * thd,const char * db)637 Events::drop_schema_events(THD *thd, const char *db)
638 {
639   LEX_STRING db_lex= { const_cast<char*>(db), strlen(db) };
640 
641   DBUG_ENTER("Events::drop_schema_events");
642   DBUG_PRINT("enter", ("dropping events from %s", db));
643 
644   /*
645     Sic: no check if the scheduler is disabled or system tables
646     are damaged, as intended.
647   */
648   if (event_queue)
649     event_queue->drop_schema_events(thd, db_lex);
650   db_repository->drop_schema_events(thd, db_lex);
651 
652   DBUG_VOID_RETURN;
653 }
654 
655 
656 /**
657   A helper function to generate SHOW CREATE EVENT output from
658   a named event
659 */
660 
661 static bool
send_show_create_event(THD * thd,Event_timed * et,Protocol * protocol)662 send_show_create_event(THD *thd, Event_timed *et, Protocol *protocol)
663 {
664   char show_str_buf[10 * STRING_BUFFER_USUAL_SIZE];
665   String show_str(show_str_buf, sizeof(show_str_buf), system_charset_info);
666   List<Item> field_list;
667   LEX_STRING sql_mode;
668   const String *tz_name;
669 
670   DBUG_ENTER("send_show_create_event");
671 
672   show_str.length(0);
673   if (et->get_create_event(thd, &show_str))
674     DBUG_RETURN(TRUE);
675 
676   field_list.push_back(new Item_empty_string("Event", NAME_CHAR_LEN));
677 
678   if (sql_mode_string_representation(thd, et->sql_mode, &sql_mode))
679     DBUG_RETURN(TRUE);
680 
681   field_list.push_back(new Item_empty_string("sql_mode", (uint) sql_mode.length));
682 
683   tz_name= et->time_zone->get_name();
684 
685   field_list.push_back(new Item_empty_string("time_zone",
686                                              tz_name->length()));
687 
688   field_list.push_back(new Item_empty_string("Create Event",
689                                              show_str.length()));
690 
691   field_list.push_back(
692     new Item_empty_string("character_set_client", MY_CS_NAME_SIZE));
693 
694   field_list.push_back(
695     new Item_empty_string("collation_connection", MY_CS_NAME_SIZE));
696 
697   field_list.push_back(
698     new Item_empty_string("Database Collation", MY_CS_NAME_SIZE));
699 
700   if (thd->send_result_metadata(&field_list,
701                                 Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
702     DBUG_RETURN(TRUE);
703 
704   protocol->start_row();
705 
706   protocol->store(et->name.str, et->name.length, system_charset_info);
707   protocol->store(sql_mode.str, sql_mode.length, system_charset_info);
708   protocol->store(tz_name->ptr(), tz_name->length(), system_charset_info);
709   protocol->store(show_str.c_ptr(), show_str.length(),
710                   et->creation_ctx->get_client_cs());
711   protocol->store(et->creation_ctx->get_client_cs()->csname,
712                   strlen(et->creation_ctx->get_client_cs()->csname),
713                   system_charset_info);
714   protocol->store(et->creation_ctx->get_connection_cl()->name,
715                   strlen(et->creation_ctx->get_connection_cl()->name),
716                   system_charset_info);
717   protocol->store(et->creation_ctx->get_db_cl()->name,
718                   strlen(et->creation_ctx->get_db_cl()->name),
719                   system_charset_info);
720 
721   if (protocol->end_row())
722     DBUG_RETURN(TRUE);
723 
724   my_eof(thd);
725 
726   DBUG_RETURN(FALSE);
727 }
728 
729 
730 /**
731   Implement SHOW CREATE EVENT statement
732 
733       thd   Thread context
734       spn   The name of the event (db, name)
735 
736   @retval  FALSE  OK
737   @retval  TRUE   error (reported)
738 */
739 
740 bool
show_create_event(THD * thd,LEX_STRING dbname,LEX_STRING name)741 Events::show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
742 {
743   Event_timed et;
744   bool ret;
745 
746   DBUG_ENTER("Events::show_create_event");
747   DBUG_PRINT("enter", ("name: %s@%s", dbname.str, name.str));
748 
749   if (check_if_system_tables_error())
750     DBUG_RETURN(TRUE);
751 
752   if (check_access(thd, EVENT_ACL, dbname.str, NULL, NULL, 0, 0))
753     DBUG_RETURN(TRUE);
754 
755   /*
756     We would like to allow SHOW CREATE EVENT under LOCK TABLES and
757     in pre-locked mode. mysql.event table is marked as a system table.
758     This flag reduces the set of its participation scenarios in LOCK TABLES
759     operation, and therefore an out-of-bound open of this table
760     for reading like the one below (sic, only for reading) is
761     more or less deadlock-free. For additional information about when a
762     deadlock can occur please refer to the description of 'system table'
763     flag.
764   */
765   ret= db_repository->load_named_event(thd, dbname, name, &et);
766 
767   if (!ret)
768     ret= send_show_create_event(thd, &et, thd->get_protocol());
769 
770   DBUG_RETURN(ret);
771 }
772 
773 
774 /**
775   Check access rights and fill INFORMATION_SCHEMA.events table.
776 
777   @param[in,out]  thd     Thread context
778   @param[in]      tables  The temporary table to fill.
779 
780   In MySQL INFORMATION_SCHEMA tables are temporary tables that are
781   created and filled on demand. In this function, we fill
782   INFORMATION_SCHEMA.events. It is a callback for I_S module, invoked from
783   sql_show.cc
784 
785   @return Has to be integer, as such is the requirement of the I_S API
786   @retval  0  success
787   @retval  1  an error, pushed into the error stack
788 */
789 
790 int
fill_schema_events(THD * thd,TABLE_LIST * tables,Item *)791 Events::fill_schema_events(THD *thd, TABLE_LIST *tables, Item * /* cond */)
792 {
793   char *db= NULL;
794   int ret;
795   DBUG_ENTER("Events::fill_schema_events");
796 
797   if (check_if_system_tables_error())
798     DBUG_RETURN(1);
799 
800   /*
801     If it's SHOW EVENTS then thd->lex->select_lex->db is guaranteed not to
802     be NULL. Let's do an assert anyway.
803   */
804   if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS)
805   {
806     db= thd->lex->select_lex->db;
807     assert(db != NULL);
808     /*
809       Nobody has EVENT_ACL for I_S and P_S,
810       even with a GRANT ALL to *.*,
811       because these schemas have additional ACL restrictions:
812       see ACL_internal_schema_registry.
813 
814       Yet there are no events in I_S and P_S to hide either,
815       so this check voluntarily does not enforce ACL for
816       SHOW EVENTS in I_S or P_S,
817       to return an empty list instead of an access denied error.
818 
819       This is more user friendly, in particular for tools.
820 
821       EVENT_ACL is not fine grained enough to differentiate:
822       - creating / updating / deleting events
823       - viewing existing events
824     */
825     if (! is_infoschema_db(db) &&
826         ! is_perfschema_db(db) &&
827         check_access(thd, EVENT_ACL, db, NULL, NULL, 0, 0))
828       DBUG_RETURN(1);
829   }
830   ret= db_repository->fill_schema_events(thd, tables, db);
831 
832   DBUG_RETURN(ret);
833 }
834 
835 
836 /**
837   Initializes the scheduler's structures.
838 
839   @param  opt_noacl_or_bootstrap
840                      TRUE if there is --skip-grant-tables or --bootstrap
841                      option. In that case we disable the event scheduler.
842 
843   @note   This function is not synchronized.
844 
845   @retval  FALSE   Perhaps there was an error, and the event scheduler
846                    is disabled. But the error is not fatal and the
847                    server start up can continue.
848   @retval  TRUE    Fatal error. Startup must terminate (call unireg_abort()).
849 */
850 
851 bool
init(my_bool opt_noacl_or_bootstrap)852 Events::init(my_bool opt_noacl_or_bootstrap)
853 {
854 
855   THD *thd;
856   int err_no;
857   bool res= FALSE;
858 
859   DBUG_ENTER("Events::init");
860 
861   /* We need a temporary THD during boot */
862   if (!(thd= new THD()))
863   {
864     res= TRUE;
865     goto end;
866   }
867   /*
868     The thread stack does not start from this function but we cannot
869     guess the real value. So better some value that doesn't assert than
870     no value.
871   */
872   thd->thread_stack= (char*) &thd;
873   thd->store_globals();
874   /*
875     Set current time for the thread that handles events.
876     Current time is stored in data member start_time of THD class.
877     Subsequently, this value is used to check whether event was expired
878     when make loading events from storage. Check for event expiration time
879     is done at Event_queue_element::compute_next_execution_time() where
880     event's status set to Event_parse_data::DISABLED and dropped flag set
881     to true if event was expired.
882   */
883   thd->set_time();
884   /*
885     We will need Event_db_repository anyway, even if the scheduler is
886     disabled - to perform events DDL.
887   */
888   if (!(db_repository= new Event_db_repository))
889   {
890     res= TRUE; /* fatal error: request unireg_abort */
891     goto end;
892   }
893 
894   /*
895     Since we allow event DDL even if the scheduler is disabled,
896     check the system tables, as we might need them.
897 
898     If run with --skip-grant-tables or --bootstrap, don't try to do the
899     check of system tables and don't complain: in these modes the tables
900     are most likely not there and we're going to disable the event
901     scheduler anyway.
902   */
903   if (opt_noacl_or_bootstrap || Event_db_repository::check_system_tables(thd))
904   {
905     if (! opt_noacl_or_bootstrap)
906     {
907       sql_print_error("Event Scheduler: An error occurred when initializing "
908                       "system tables. Disabling the Event Scheduler.");
909       check_system_tables_error= TRUE;
910     }
911 
912     /* Disable the scheduler since the system tables are not up to date */
913     opt_event_scheduler= EVENTS_DISABLED;
914     goto end;
915   }
916 
917   /*
918     Was disabled explicitly from the command line, or because we're running
919     with --skip-grant-tables, or --bootstrap, or because we have no system
920     tables.
921   */
922   if (opt_event_scheduler == Events::EVENTS_DISABLED)
923     goto end;
924 
925 
926   assert(opt_event_scheduler == Events::EVENTS_ON ||
927          opt_event_scheduler == Events::EVENTS_OFF);
928 
929   if (!(event_queue= new Event_queue) ||
930       !(scheduler= new Event_scheduler(event_queue)))
931   {
932     res= TRUE; /* fatal error: request unireg_abort */
933     goto end;
934   }
935 
936   if (event_queue->init_queue(thd) || load_events_from_db(thd) ||
937       (opt_event_scheduler == EVENTS_ON && scheduler->start(&err_no)))
938   {
939     sql_print_error("Event Scheduler: Error while loading from disk.");
940     res= TRUE; /* fatal error: request unireg_abort */
941     goto end;
942   }
943   Event_worker_thread::init(db_repository);
944 
945 end:
946   if (res)
947   {
948     delete db_repository;
949     db_repository= NULL;
950     delete event_queue;
951     event_queue= NULL;
952     delete scheduler;
953     scheduler= NULL;
954   }
955   delete thd;
956 
957   DBUG_RETURN(res);
958 }
959 
960 /*
961   Cleans up scheduler's resources. Called at server shutdown.
962 
963   SYNOPSIS
964     Events::deinit()
965 
966   NOTES
967     This function is not synchronized.
968 */
969 
970 void
deinit()971 Events::deinit()
972 {
973   DBUG_ENTER("Events::deinit");
974 
975   if (opt_event_scheduler != EVENTS_DISABLED)
976   {
977     delete scheduler;
978     scheduler= NULL;                            /* safety */
979     delete event_queue;
980     event_queue= NULL;                          /* safety */
981   }
982 
983   delete db_repository;
984   db_repository= NULL;                          /* safety */
985 
986   DBUG_VOID_RETURN;
987 }
988 
989 #ifdef HAVE_PSI_INTERFACE
990 PSI_mutex_key key_LOCK_event_queue,
991               key_event_scheduler_LOCK_scheduler_state;
992 
993 static PSI_mutex_info all_events_mutexes[]=
994 {
995   { &key_LOCK_event_queue, "LOCK_event_queue", PSI_FLAG_GLOBAL},
996   { &key_event_scheduler_LOCK_scheduler_state, "Event_scheduler::LOCK_scheduler_state", PSI_FLAG_GLOBAL}
997 };
998 
999 PSI_cond_key key_event_scheduler_COND_state, key_COND_queue_state;
1000 
1001 static PSI_cond_info all_events_conds[]=
1002 {
1003   { &key_event_scheduler_COND_state, "Event_scheduler::COND_state", PSI_FLAG_GLOBAL},
1004   { &key_COND_queue_state, "COND_queue_state", PSI_FLAG_GLOBAL},
1005 };
1006 
1007 PSI_thread_key key_thread_event_scheduler, key_thread_event_worker;
1008 
1009 static PSI_thread_info all_events_threads[]=
1010 {
1011   { &key_thread_event_scheduler, "event_scheduler", PSI_FLAG_GLOBAL},
1012   { &key_thread_event_worker, "event_worker", 0}
1013 };
1014 #endif /* HAVE_PSI_INTERFACE */
1015 
1016 PSI_stage_info stage_waiting_on_empty_queue= { 0, "Waiting on empty queue", 0};
1017 PSI_stage_info stage_waiting_for_next_activation= { 0, "Waiting for next activation", 0};
1018 PSI_stage_info stage_waiting_for_scheduler_to_stop= { 0, "Waiting for the scheduler to stop", 0};
1019 
1020 PSI_memory_key key_memory_event_basic_root;
1021 
1022 #ifdef HAVE_PSI_INTERFACE
1023 PSI_stage_info *all_events_stages[]=
1024 {
1025   & stage_waiting_on_empty_queue,
1026   & stage_waiting_for_next_activation,
1027   & stage_waiting_for_scheduler_to_stop
1028 };
1029 
1030 static PSI_memory_info all_events_memory[]=
1031 {
1032   { &key_memory_event_basic_root, "Event_basic::mem_root", PSI_FLAG_GLOBAL}
1033 };
1034 
init_events_psi_keys(void)1035 static void init_events_psi_keys(void)
1036 {
1037   const char* category= "sql";
1038   int count;
1039 
1040   count= array_elements(all_events_mutexes);
1041   mysql_mutex_register(category, all_events_mutexes, count);
1042 
1043   count= array_elements(all_events_conds);
1044   mysql_cond_register(category, all_events_conds, count);
1045 
1046   count= array_elements(all_events_threads);
1047   mysql_thread_register(category, all_events_threads, count);
1048 
1049   count= array_elements(all_events_stages);
1050   mysql_stage_register(category, all_events_stages, count);
1051 
1052   count= array_elements(all_events_memory);
1053   mysql_memory_register(category, all_events_memory, count);
1054 }
1055 #endif /* HAVE_PSI_INTERFACE */
1056 
1057 /**
1058   Inits Events mutexes
1059 
1060   SYNOPSIS
1061     Events::init_mutexes()
1062       thd  Thread
1063 */
1064 
1065 void
init_mutexes()1066 Events::init_mutexes()
1067 {
1068 #ifdef HAVE_PSI_INTERFACE
1069   init_events_psi_keys();
1070 #endif
1071 }
1072 
1073 
1074 /*
1075   Dumps the internal status of the scheduler and the memory cache
1076   into a table with two columns - Name & Value. Different properties
1077   which could be useful for debugging for instance deadlocks are
1078   returned.
1079 
1080   SYNOPSIS
1081     Events::dump_internal_status()
1082 */
1083 
1084 void
dump_internal_status()1085 Events::dump_internal_status()
1086 {
1087   DBUG_ENTER("Events::dump_internal_status");
1088   puts("\n\n\nEvents status:");
1089   puts("LLA = Last Locked At  LUA = Last Unlocked At");
1090   puts("WOC = Waiting On Condition  DL = Data Locked");
1091 
1092   /*
1093     opt_event_scheduler should only be accessed while
1094     holding LOCK_global_system_variables.
1095   */
1096   mysql_mutex_lock(&LOCK_global_system_variables);
1097   if (opt_event_scheduler == EVENTS_DISABLED)
1098     puts("The Event Scheduler is disabled");
1099   else
1100   {
1101     scheduler->dump_internal_status();
1102     event_queue->dump_internal_status();
1103   }
1104 
1105   mysql_mutex_unlock(&LOCK_global_system_variables);
1106   DBUG_VOID_RETURN;
1107 }
1108 
start(int * err_no)1109 bool Events::start(int *err_no)
1110 {
1111   bool ret= false;
1112   if (scheduler) ret= scheduler->start(err_no);
1113   return ret;
1114 }
1115 
stop()1116 bool Events::stop()
1117 {
1118   bool ret= false;
1119   if (scheduler) ret= scheduler->stop();
1120   return ret;
1121 }
1122 
1123 /**
1124   Loads all ENABLED events from mysql.event into a prioritized
1125   queue.
1126 
1127   This function is called during the server start up. It reads
1128   every event, computes the next execution time, and if the event
1129   needs execution, adds it to a prioritized queue. Otherwise, if
1130   ON COMPLETION DROP is specified, the event is automatically
1131   removed from the table.
1132 
1133   @param[in,out] thd Thread context. Used for memory allocation in some cases.
1134 
1135   @retval  FALSE  success
1136   @retval  TRUE   error, the load is aborted
1137 
1138   @note Reports the error to the console
1139 */
1140 
1141 bool
load_events_from_db(THD * thd)1142 Events::load_events_from_db(THD *thd)
1143 {
1144   TABLE *table;
1145   READ_RECORD read_record_info;
1146   bool ret= TRUE;
1147   uint count= 0;
1148   ulong saved_master_access;
1149 
1150   DBUG_ENTER("Events::load_events_from_db");
1151   DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
1152 
1153   /*
1154     NOTE: even if we run in read-only mode, we should be able to lock the
1155     mysql.event table for writing. In order to achieve this, we should call
1156     mysql_lock_tables() under the super user.
1157 
1158     Same goes for transaction access mode.
1159     Temporarily reset it to read-write.
1160   */
1161 
1162   saved_master_access= thd->security_context()->master_access();
1163   thd->security_context()->set_master_access(saved_master_access | SUPER_ACL);
1164   bool save_tx_read_only= thd->tx_read_only;
1165   thd->tx_read_only= false;
1166 
1167   ret= db_repository->open_event_table(thd, TL_WRITE, &table);
1168 
1169   thd->tx_read_only= save_tx_read_only;
1170   thd->security_context()->set_master_access(saved_master_access);
1171 
1172   if (ret)
1173   {
1174     sql_print_error("Event Scheduler: Failed to open table mysql.event");
1175     DBUG_RETURN(TRUE);
1176   }
1177 
1178   if (init_read_record(&read_record_info, thd, table, NULL, 0, 1, FALSE))
1179   {
1180     sql_print_error("Event Scheduler: Error while starting read of mysql.event");
1181     DBUG_RETURN(TRUE);
1182   }
1183   while (!(read_record_info.read_record(&read_record_info)))
1184   {
1185     Event_queue_element *et;
1186     bool created, dropped;
1187 
1188     if (!(et= new Event_queue_element))
1189       goto end;
1190 
1191     DBUG_PRINT("info", ("Loading event from row."));
1192 
1193     if (et->load_from_row(thd, table))
1194     {
1195       sql_print_error("Event Scheduler: "
1196                       "Error while loading events from mysql.event. "
1197                       "The table probably contains bad data or is corrupted");
1198       delete et;
1199       goto end;
1200     }
1201 
1202     /**
1203       Since the Event_queue_element object could be deleted inside
1204       Event_queue::create_event we should save the value of dropped flag
1205       into the temporary variable.
1206     */
1207     dropped= et->dropped;
1208     if (event_queue->create_event(thd, et, &created))
1209     {
1210       /* Out of memory */
1211       delete et;
1212       goto end;
1213     }
1214     if (created)
1215       count++;
1216     else if (dropped)
1217     {
1218       /*
1219         If not created, a stale event - drop if immediately if
1220         ON COMPLETION NOT PRESERVE.
1221         XXX: This won't be replicated, thus the drop won't appear in
1222              in the slave. When the slave is restarted it will drop events.
1223              However, as the slave will be "out of sync", it might happen that
1224              an event created on the master, after master restart, won't be
1225              replicated to the slave correctly, as the create will fail there.
1226       */
1227       int rc= table->file->ha_delete_row(table->record[0]);
1228       if (rc)
1229       {
1230         table->file->print_error(rc, MYF(0));
1231         goto end;
1232       }
1233     }
1234   }
1235   sql_print_information("Event Scheduler: Loaded %d event%s",
1236                         count, (count == 1) ? "" : "s");
1237   ret= FALSE;
1238 
1239 end:
1240   end_read_record(&read_record_info);
1241 
1242   close_mysql_tables(thd);
1243   DBUG_RETURN(ret);
1244 }
1245 
1246 /**
1247   @} (End of group Event_Scheduler)
1248 */
1249