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