1 /*
2    Copyright (c) 2005, 2010, 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 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-1335  USA */
16 
17 #define MYSQL_LEX 1
18 #include "mariadb.h"                          /* NO_EMBEDDED_ACCESS_CHECKS */
19 #include "sql_priv.h"
20 #include "unireg.h"
21 #include "sql_parse.h"                          // parse_sql
22 #include "strfunc.h"                           // find_string_in_array
23 #include "sql_db.h"                        // get_default_db_collation
24 #include "sql_time.h"                      // interval_type_to_name,
25                                            // date_add_interval,
26                                            // calc_time_diff
27 #include "tztime.h"     // my_tz_find, my_tz_OFFSET0, struct Time_zone
28 #include "sql_acl.h"    // EVENT_ACL, SUPER_ACL
29 #include "sp.h"         // load_charset, load_collation
30 #include "events.h"
31 #include "event_data_objects.h"
32 #include "event_db_repository.h"
33 #include "sp_head.h"
effects_start_allocation(y_synth_t * synth)34 #include "sql_show.h"                // append_definer, append_identifier
35 #ifdef WITH_WSREP
36 #include "wsrep_trans_observer.h"
37 #endif /* WITH_WSREP */
38 /**
39   @addtogroup Event_Scheduler
40   @{
41 */
42 
43 /*************************************************************************/
44 
45 /**
46   Event_creation_ctx -- creation context of events.
47 */
48 
49 class Event_creation_ctx :public Stored_program_creation_ctx,
50                           public Sql_alloc
51 {
52 public:
53   static bool load_from_db(THD *thd,
54                            MEM_ROOT *event_mem_root,
55                            const char *db_name,
56                            const char *event_name,
57                            TABLE *event_tbl,
58                            Stored_program_creation_ctx **ctx);
59 
60 public:
61   virtual Stored_program_creation_ctx *clone(MEM_ROOT *mem_root)
62   {
63     return new (mem_root)
64                Event_creation_ctx(m_client_cs, m_connection_cl, m_db_cl);
65   }
66 
67 protected:
68   virtual Object_creation_ctx *create_backup_ctx(THD *thd) const
69   {
70     /*
71       We can avoid usual backup/restore employed in stored programs since we
72       know that this is a top level statement and the worker thread is
73       allocated exclusively to execute this event.
74     */
75 
76     return NULL;
77   }
78 
79 private:
80   Event_creation_ctx(CHARSET_INFO *client_cs,
81                      CHARSET_INFO *connection_cl,
82                      CHARSET_INFO *db_cl)
83     : Stored_program_creation_ctx(client_cs, connection_cl, db_cl)
84   { }
85 };
86 
87 /**************************************************************************
88   Event_creation_ctx implementation.
89 **************************************************************************/
90 
91 bool
92 Event_creation_ctx::load_from_db(THD *thd,
93                                  MEM_ROOT *event_mem_root,
94                                  const char *db_name,
95                                  const char *event_name,
96                                  TABLE *event_tbl,
97                                  Stored_program_creation_ctx **ctx)
98 {
99   /* Load character set/collation attributes. */
100 
101   CHARSET_INFO *client_cs;
102   CHARSET_INFO *connection_cl;
103   CHARSET_INFO *db_cl;
104 
105   bool invalid_creation_ctx= FALSE;
106 
107   if (load_charset(event_mem_root,
108                    event_tbl->field[ET_FIELD_CHARACTER_SET_CLIENT],
109                    thd->variables.character_set_client,
110                    &client_cs))
111   {
112     sql_print_warning("Event '%s'.'%s': invalid value "
113                       "in column mysql.event.character_set_client.",
114                       (const char *) db_name,
115                       (const char *) event_name);
116 
117     invalid_creation_ctx= TRUE;
118   }
119 
120   if (load_collation(event_mem_root,
121                      event_tbl->field[ET_FIELD_COLLATION_CONNECTION],
122                      thd->variables.collation_connection,
123                      &connection_cl))
124   {
125     sql_print_warning("Event '%s'.'%s': invalid value "
126                       "in column mysql.event.collation_connection.",
127                       (const char *) db_name,
128                       (const char *) event_name);
129 
130     invalid_creation_ctx= TRUE;
131   }
132 
133   if (load_collation(event_mem_root,
134                      event_tbl->field[ET_FIELD_DB_COLLATION],
135                      NULL,
136                      &db_cl))
137   {
138     sql_print_warning("Event '%s'.'%s': invalid value "
139                       "in column mysql.event.db_collation.",
140                       (const char *) db_name,
141                       (const char *) event_name);
142 
143     invalid_creation_ctx= TRUE;
144   }
145 
146   /*
147     If we failed to resolve the database collation, load the default one
148     from the disk.
149   */
150 
151   if (!db_cl)
152     db_cl= get_default_db_collation(thd, db_name);
153 
154   /* Create the context. */
155 
156   *ctx= new Event_creation_ctx(client_cs, connection_cl, db_cl);
157 
158   return invalid_creation_ctx;
159 }
160 
161 /*************************************************************************/
162 
163 /*
164   Initializes dbname and name of an Event_queue_element_for_exec
165   object
166 
167   SYNOPSIS
168     Event_queue_element_for_exec::init()
169 
170   RETURN VALUE
171     FALSE  OK
172     TRUE   Error (OOM)
173 */
174 
175 bool
176 Event_queue_element_for_exec::init(const LEX_CSTRING *db, const LEX_CSTRING *n)
177 {
178   if (!(dbname.str= my_strndup(db->str, dbname.length= db->length, MYF(MY_WME))))
179     return TRUE;
180   if (!(name.str= my_strndup(n->str, name.length= n->length, MYF(MY_WME))))
181   {
182     my_free(const_cast<char*>(dbname.str));
183     dbname.str= NULL;
184     return TRUE;
185   }
186   return FALSE;
187 }
188 
189 
190 /*
191   Destructor
192 
193   SYNOPSIS
194     Event_queue_element_for_exec::~Event_queue_element_for_exec()
195 */
196 
197 Event_queue_element_for_exec::~Event_queue_element_for_exec()
198 {
199   my_free(const_cast<char*>(dbname.str));
200   my_free(const_cast<char*>(name.str));
201 }
202 
203 
204 /*
205   Constructor
206 
207   SYNOPSIS
208     Event_basic::Event_basic()
209 */
210 
211 Event_basic::Event_basic()
212 {
213   DBUG_ENTER("Event_basic::Event_basic");
214   /* init memory root */
215   init_sql_alloc(&mem_root, "Event_basic", 256, 512, MYF(0));
216   dbname.str= name.str= NULL;
217   dbname.length= name.length= 0;
218   time_zone= NULL;
219   DBUG_VOID_RETURN;
220 }
221 
222 
223 /*
224   Destructor
225 
226   SYNOPSIS
227     Event_basic::Event_basic()
228 */
229 
230 Event_basic::~Event_basic()
231 {
232   DBUG_ENTER("Event_basic::~Event_basic");
233   free_root(&mem_root, MYF(0));
234   DBUG_VOID_RETURN;
235 }
236 
237 
238 /*
239   Short function to load a char column into a LEX_CSTRING
240 
241   SYNOPSIS
242     Event_basic::load_string_field()
243       field_name  The field( enum_events_table_field is not actually used
244                   because it's unknown in event_data_objects.h)
245       fields      The Field array
246       field_value The value
247 */
248 
249 bool
250 Event_basic::load_string_fields(Field **fields, ...)
251 {
252   bool ret= FALSE;
253   va_list args;
254   enum enum_events_table_field field_name;
255   LEX_CSTRING *field_value;
256 
257   DBUG_ENTER("Event_basic::load_string_fields");
258 
259   va_start(args, fields);
260   field_name= (enum enum_events_table_field) va_arg(args, int);
261   while (field_name < ET_FIELD_COUNT)
262   {
263     field_value= va_arg(args, LEX_CSTRING *);
264     if ((field_value->str= get_field(&mem_root, fields[field_name])) == NullS)
265     {
266       ret= TRUE;
267       break;
268     }
269     field_value->length= strlen(field_value->str);
270 
271     field_name= (enum enum_events_table_field) va_arg(args, int);
272   }
273   va_end(args);
274 
275   DBUG_RETURN(ret);
276 }
277 
278 
279 bool
280 Event_basic::load_time_zone(THD *thd, const LEX_CSTRING *tz_name)
281 {
282   String str(tz_name->str, &my_charset_latin1);
283   time_zone= my_tz_find(thd, &str);
284 
285   return (time_zone == NULL);
286 }
287 
288 
289 /*
290   Constructor
291 
292   SYNOPSIS
293     Event_queue_element::Event_queue_element()
294 */
295 
296 Event_queue_element::Event_queue_element():
297   on_completion(Event_parse_data::ON_COMPLETION_DROP),
298   status(Event_parse_data::ENABLED), expression(0), dropped(FALSE),
299   execution_count(0)
300 {
301   DBUG_ENTER("Event_queue_element::Event_queue_element");
302 
303   starts= ends= execute_at= last_executed= 0;
304   starts_null= ends_null= execute_at_null= TRUE;
305 
306   DBUG_VOID_RETURN;
307 }
308 
309 
310 /*
311   Destructor
312 
313   SYNOPSIS
314     Event_queue_element::Event_queue_element()
315 */
316 Event_queue_element::~Event_queue_element()
317 {
318 }
319 
320 
321 /*
322   Constructor
323 
324   SYNOPSIS
325     Event_timed::Event_timed()
326 */
327 
328 Event_timed::Event_timed():
329   created(0), modified(0), sql_mode(0)
330 {
331   DBUG_ENTER("Event_timed::Event_timed");
332   init();
333   DBUG_VOID_RETURN;
334 }
335 
336 
337 /*
338   Destructor
339 
340   SYNOPSIS
341     Event_timed::~Event_timed()
342 */
343 
344 Event_timed::~Event_timed()
345 {
346 }
347 
348 
349 /*
350   Constructor
351 
352   SYNOPSIS
353     Event_job_data::Event_job_data()
354 */
355 
356 Event_job_data::Event_job_data()
357   :sql_mode(0)
358 {
359 }
360 
361 /*
362   Init all member variables
363 
364   SYNOPSIS
365     Event_timed::init()
366 */
367 
368 void
369 Event_timed::init()
370 {
371   DBUG_ENTER("Event_timed::init");
372 
373   definer_user.str= definer_host.str= body.str= comment.str= NULL;
374   definer_user.length= definer_host.length= body.length= comment.length= 0;
375 
376   sql_mode= 0;
377 
378   DBUG_VOID_RETURN;
379 }
380 
381 
382 /**
383   Load an event's body from a row from mysql.event.
384 
385   @details This method is silent on errors and should behave like that.
386   Callers should handle throwing of error messages. The reason is that the
387   class should not know about how to deal with communication.
388 
389   @return Operation status
390     @retval FALSE OK
391     @retval TRUE  Error
392 */
393 
394 bool
395 Event_job_data::load_from_row(THD *thd, TABLE *table)
396 {
397   const char *ptr;
398   size_t len;
399   LEX_CSTRING tz_name;
400 
401   DBUG_ENTER("Event_job_data::load_from_row");
402 
403   if (!table)
404     DBUG_RETURN(TRUE);
405 
406   if (table->s->fields < ET_FIELD_COUNT)
407     DBUG_RETURN(TRUE);
408 
409   if (load_string_fields(table->field,
410                          ET_FIELD_DB, &dbname,
411                          ET_FIELD_NAME, &name,
412                          ET_FIELD_BODY, &body,
413                          ET_FIELD_DEFINER, &definer,
414                          ET_FIELD_TIME_ZONE, &tz_name,
415                          ET_FIELD_COUNT))
416     DBUG_RETURN(TRUE);
417 
418   if (load_time_zone(thd, &tz_name))
419     DBUG_RETURN(TRUE);
420 
421   Event_creation_ctx::load_from_db(thd, &mem_root, dbname.str, name.str, table,
422                                    &creation_ctx);
423 
424   ptr= strchr(definer.str, '@');
425 
426   if (! ptr)
427     ptr= definer.str;
428 
429   len= ptr - definer.str;
430   definer_user.str= strmake_root(&mem_root, definer.str, len);
431   definer_user.length= len;
432   len= definer.length - len - 1;
433   /* 1:because of @ */
434   definer_host.str= strmake_root(&mem_root, ptr + 1, len);
435   definer_host.length= len;
436 
437   sql_mode= (sql_mode_t) table->field[ET_FIELD_SQL_MODE]->val_int();
438 
439   DBUG_RETURN(FALSE);
440 }
441 
442 
443 /**
444   Load an event's body from a row from mysql.event.
445 
446   @details This method is silent on errors and should behave like that.
447   Callers should handle throwing of error messages. The reason is that the
448   class should not know about how to deal with communication.
449 
450   @return Operation status
451     @retval FALSE OK
452     @retval TRUE  Error
453 */
454 
455 bool
456 Event_queue_element::load_from_row(THD *thd, TABLE *table)
457 {
458   const char *ptr;
459   MYSQL_TIME time;
460   LEX_CSTRING tz_name;
461 
462   DBUG_ENTER("Event_queue_element::load_from_row");
463 
464   if (!table)
465     DBUG_RETURN(TRUE);
466 
467   if (table->s->fields < ET_FIELD_COUNT)
468     DBUG_RETURN(TRUE);
469 
470   if (load_string_fields(table->field,
471                          ET_FIELD_DB, &dbname,
472                          ET_FIELD_NAME, &name,
473                          ET_FIELD_DEFINER, &definer,
474                          ET_FIELD_TIME_ZONE, &tz_name,
475                          ET_FIELD_COUNT))
476     DBUG_RETURN(TRUE);
477 
478   if (load_time_zone(thd, &tz_name))
479     DBUG_RETURN(TRUE);
480 
481   starts_null= table->field[ET_FIELD_STARTS]->is_null();
482   uint not_used;
483   if (!starts_null)
484   {
485     /*
486       The expected data type for these columns in mysql.events:
487         starts, ends, execute_at, last_executed
488       is DATETIME. No nanosecond truncation should normally be needed,
489       unless the DBA changes them, e.g. to VARCHAR, DECIMAL, etc.
490       For this unexpected case let's use the default round mode,
491       according to the current session settings.
492     */
493     table->field[ET_FIELD_STARTS]->get_date(&time, TIME_NO_ZERO_DATE |
494                                                    thd->temporal_round_mode());
495     starts= my_tz_OFFSET0->TIME_to_gmt_sec(&time,&not_used);
496   }
497 
498   ends_null= table->field[ET_FIELD_ENDS]->is_null();
499   if (!ends_null)
500   {
501     table->field[ET_FIELD_ENDS]->get_date(&time, TIME_NO_ZERO_DATE |
502                                                  thd->temporal_round_mode());
503     ends= my_tz_OFFSET0->TIME_to_gmt_sec(&time,&not_used);
504   }
505 
506   if (!table->field[ET_FIELD_INTERVAL_EXPR]->is_null())
507     expression= table->field[ET_FIELD_INTERVAL_EXPR]->val_int();
508   else
509     expression= 0;
510   /*
511     If neigher STARTS and ENDS is set, then both fields are empty.
512     Hence, if ET_FIELD_EXECUTE_AT is empty there is an error.
513   */
514   execute_at_null= table->field[ET_FIELD_EXECUTE_AT]->is_null();
515   DBUG_ASSERT(!(starts_null && ends_null && !expression && execute_at_null));
516   if (!expression && !execute_at_null)
517   {
518     if (table->field[ET_FIELD_EXECUTE_AT]->get_date(&time, TIME_NO_ZERO_DATE |
519                                                     thd->temporal_round_mode()))
520       DBUG_RETURN(TRUE);
521     execute_at= my_tz_OFFSET0->TIME_to_gmt_sec(&time,&not_used);
522   }
523 
524   /*
525     We load the interval type from disk as string and then map it to
526     an integer. This decouples the values of enum interval_type
527     and values actually stored on disk. Therefore the type can be
528     reordered without risking incompatibilities of data between versions.
529   */
530   if (!table->field[ET_FIELD_TRANSIENT_INTERVAL]->is_null())
531   {
532     int i;
533     char buff[MAX_FIELD_WIDTH];
534     String str(buff, sizeof(buff), &my_charset_bin);
535     LEX_CSTRING tmp;
536 
537     table->field[ET_FIELD_TRANSIENT_INTERVAL]->val_str(&str);
538     if (!(tmp.length= str.length()))
539       DBUG_RETURN(TRUE);
540 
541     tmp.str= str.c_ptr_safe();
542 
543     i= find_string_in_array(interval_type_to_name, &tmp, system_charset_info);
544     if (i < 0)
545       DBUG_RETURN(TRUE);
546     interval= (interval_type) i;
547   }
548 
549   if (!table->field[ET_FIELD_LAST_EXECUTED]->is_null())
550   {
551     table->field[ET_FIELD_LAST_EXECUTED]->get_date(&time, TIME_NO_ZERO_DATE |
552                                                    thd->temporal_round_mode());
553     last_executed= my_tz_OFFSET0->TIME_to_gmt_sec(&time,&not_used);
554   }
555 
556   if ((ptr= get_field(&mem_root, table->field[ET_FIELD_STATUS])) == NullS)
557     DBUG_RETURN(TRUE);
558 
559   DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", name.str, ptr));
560 
561   /* Set event status (ENABLED | SLAVESIDE_DISABLED | DISABLED) */
562   switch (ptr[0])
563   {
564   case 'E' :
565     status = Event_parse_data::ENABLED;
566     break;
567   case 'S' :
568     status = Event_parse_data::SLAVESIDE_DISABLED;
569     break;
570   case 'D' :
571   default:
572     status = Event_parse_data::DISABLED;
573     break;
574   }
575   if ((ptr= get_field(&mem_root, table->field[ET_FIELD_ORIGINATOR])) == NullS)
576     DBUG_RETURN(TRUE);
577   originator = (uint32) table->field[ET_FIELD_ORIGINATOR]->val_int();
578 
579   /* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
580   if ((ptr= get_field(&mem_root,
581                       table->field[ET_FIELD_ON_COMPLETION])) == NullS)
582     DBUG_RETURN(TRUE);
583 
584   on_completion= (ptr[0]=='D'? Event_parse_data::ON_COMPLETION_DROP:
585                                Event_parse_data::ON_COMPLETION_PRESERVE);
586 
587   DBUG_RETURN(FALSE);
588 }
589 
590 
591 /**
592   Load an event's body from a row from mysql.event.
593 
594   @details This method is silent on errors and should behave like that.
595   Callers should handle throwing of error messages. The reason is that the
596   class should not know about how to deal with communication.
597 
598   @return Operation status
599     @retval FALSE OK
600     @retval TRUE  Error
601 */
602 
603 bool
604 Event_timed::load_from_row(THD *thd, TABLE *table)
605 {
606   const char *ptr;
607   size_t len;
608 
609   DBUG_ENTER("Event_timed::load_from_row");
610 
611   if (Event_queue_element::load_from_row(thd, table))
612     DBUG_RETURN(TRUE);
613 
614   if (load_string_fields(table->field,
615                          ET_FIELD_BODY, &body,
616                          ET_FIELD_BODY_UTF8, &body_utf8,
617                          ET_FIELD_COUNT))
618     DBUG_RETURN(TRUE);
619 
620   if (Event_creation_ctx::load_from_db(thd, &mem_root, dbname.str, name.str,
621                                        table, &creation_ctx))
622   {
623     push_warning_printf(thd,
624                         Sql_condition::WARN_LEVEL_WARN,
625                         ER_EVENT_INVALID_CREATION_CTX,
626                         ER_THD(thd, ER_EVENT_INVALID_CREATION_CTX),
627                         (const char *) dbname.str,
628                         (const char *) name.str);
629   }
630 
631   ptr= strchr(definer.str, '@');
632 
633   if (! ptr)
634     ptr= definer.str;
635 
636   len= ptr - definer.str;
637   definer_user.str= strmake_root(&mem_root, definer.str, len);
638   definer_user.length= len;
639   len= definer.length - len - 1;
640   /* 1:because of @ */
641   definer_host.str= strmake_root(&mem_root, ptr + 1,  len);
642   definer_host.length= len;
643 
644   created= table->field[ET_FIELD_CREATED]->val_int();
645   modified= table->field[ET_FIELD_MODIFIED]->val_int();
646 
647   comment.str= get_field(&mem_root, table->field[ET_FIELD_COMMENT]);
648   if (comment.str != NullS)
649     comment.length= strlen(comment.str);
650   else
651     comment.length= 0;
652 
653   sql_mode= (sql_mode_t) table->field[ET_FIELD_SQL_MODE]->val_int();
654 
655   DBUG_RETURN(FALSE);
656 }
657 
658 
659 /*
660   add_interval() adds a specified interval to time 'ltime' in time
661   zone 'time_zone', and returns the result converted to the number of
662   seconds since epoch (aka Unix time; in UTC time zone).  Zero result
663   means an error.
664 */
665 static
666 my_time_t
667 add_interval(MYSQL_TIME *ltime, const Time_zone *time_zone,
668              interval_type scale, INTERVAL interval)
669 {
670   if (date_add_interval(current_thd, ltime, scale, interval))
671     return 0;
672 
673   uint not_used;
674   return time_zone->TIME_to_gmt_sec(ltime, &not_used);
675 }
676 
677 
678 /*
679   Computes the sum of a timestamp plus interval.
680 
681   SYNOPSIS
682     get_next_time()
683       time_zone     event time zone
684       next          the sum
685       start         add interval_value to this time
686       time_now      current time
687       i_value       quantity of time type interval to add
688       i_type        type of interval to add (SECOND, MINUTE, HOUR, WEEK ...)
689 
690   RETURN VALUE
691     0  OK
692     1  Error
693 
694   NOTES
695     1) If the interval is conversible to SECOND, like MINUTE, HOUR, DAY, WEEK.
696        Then we use TIMEDIFF()'s implementation as underlying and number of
697        seconds as resolution for computation.
698     2) In all other cases - MONTH, QUARTER, YEAR we use MONTH as resolution
699        and PERIOD_DIFF()'s implementation
700 */
701 
702 static
703 bool get_next_time(const Time_zone *time_zone, my_time_t *next,
704                    my_time_t start, my_time_t time_now,
705                    int i_value, interval_type i_type)
706 {
707   DBUG_ENTER("get_next_time");
708   DBUG_PRINT("enter", ("start: %lu  now: %lu", (long) start, (long) time_now));
709 
710   DBUG_ASSERT(start <= time_now);
711 
712   longlong months=0, seconds=0;
713 
714   switch (i_type) {
715   case INTERVAL_YEAR:
716     months= i_value*12;
717     break;
718   case INTERVAL_QUARTER:
719     /* Has already been converted to months */
720   case INTERVAL_YEAR_MONTH:
721   case INTERVAL_MONTH:
722     months= i_value;
723     break;
724   case INTERVAL_WEEK:
725     /* WEEK has already been converted to days */
726   case INTERVAL_DAY:
727     seconds= i_value*24*3600;
728     break;
729   case INTERVAL_DAY_HOUR:
730   case INTERVAL_HOUR:
731     seconds= i_value*3600;
732     break;
733   case INTERVAL_DAY_MINUTE:
734   case INTERVAL_HOUR_MINUTE:
735   case INTERVAL_MINUTE:
736     seconds= i_value*60;
737     break;
738   case INTERVAL_DAY_SECOND:
739   case INTERVAL_HOUR_SECOND:
740   case INTERVAL_MINUTE_SECOND:
741   case INTERVAL_SECOND:
742     seconds= i_value;
743     break;
744   case INTERVAL_DAY_MICROSECOND:
745   case INTERVAL_HOUR_MICROSECOND:
746   case INTERVAL_MINUTE_MICROSECOND:
747   case INTERVAL_SECOND_MICROSECOND:
748   case INTERVAL_MICROSECOND:
749     /*
750      We should return an error here so SHOW EVENTS/ SELECT FROM I_S.EVENTS
751      would give an error then.
752     */
753     DBUG_RETURN(1);
754   case INTERVAL_LAST:
755     DBUG_ASSERT(0);
756   }
757   DBUG_PRINT("info", ("seconds: %ld  months: %ld", (long) seconds, (long) months));
758 
759   MYSQL_TIME local_start;
760   MYSQL_TIME local_now;
761 
762   /* Convert times from UTC to local. */
763   {
764     time_zone->gmt_sec_to_TIME(&local_start, start);
765     time_zone->gmt_sec_to_TIME(&local_now, time_now);
766   }
767 
768   INTERVAL interval;
769   bzero(&interval, sizeof(interval));
770   my_time_t next_time= 0;
771 
772   if (seconds)
773   {
774     ulonglong seconds_diff;
775     ulong microsec_diff;
776     bool negative= calc_time_diff(&local_now, &local_start, 1,
777                                   &seconds_diff, &microsec_diff);
778     if (!negative)
779     {
780       /*
781         The formula below returns the interval that, when added to
782         local_start, will always give the time in the future.
783       */
784       interval.second= seconds_diff - seconds_diff % seconds + seconds;
785       next_time= add_interval(&local_start, time_zone,
786                               INTERVAL_SECOND, interval);
787       if (next_time == 0)
788         goto done;
789     }
790 
791     if (next_time <= time_now)
792     {
793       /*
794         If 'negative' is true above, then 'next_time == 0', and
795         'next_time <= time_now' is also true.  If negative is false,
796         then next_time was set, but perhaps to the value that is less
797         then time_now.  See below for elaboration.
798       */
799       DBUG_ASSERT(negative || next_time > 0);
800 
801       /*
802         If local_now < local_start, i.e. STARTS time is in the future
803         according to the local time (it always in the past according
804         to UTC---this is a prerequisite of this function), then
805         STARTS is almost always in the past according to the local
806         time too.  However, in the time zone that has backward
807         Daylight Saving Time shift, the following may happen: suppose
808         we have a backward DST shift at certain date after 2:59:59,
809         i.e. local time goes 1:59:59, 2:00:00, ... , 2:59:59, (shift
810         here) 2:00:00 (again), ... , 2:59:59 (again), 3:00:00, ... .
811         Now suppose the time has passed the first 2:59:59, has been
812         shifted backward, and now is (the second) 2:20:00.  The user
813         does CREATE EVENT with STARTS 'current-date 2:40:00'.  Local
814         time 2:40:00 from create statement is treated by time
815         functions as the first such time, so according to UTC it comes
816         before the second 2:20:00.  But according to local time it is
817         obviously in the future, so we end up in this branch.
818 
819         Since we are in the second pass through 2:00:00--2:59:59, and
820         any local time form this interval is treated by system
821         functions as the time from the first pass, we have to find the
822         time for the next execution that is past the DST-affected
823         interval (past the second 2:59:59 for our example,
824         i.e. starting from 3:00:00).  We do this in the loop until the
825         local time is mapped onto future UTC time.  'start' time is in
826         the past, so we may use 'do { } while' here, and add the first
827         interval right away.
828 
829         Alternatively, it could be that local_now >= local_start.  Now
830         for the example above imagine we do CREATE EVENT with STARTS
831         'current-date 2:10:00'.  Local start 2:10 is in the past (now
832         is local 2:20), so we add an interval, and get next execution
833         time, say, 2:40.  It is in the future according to local time,
834         but, again, since we are in the second pass through
835         2:00:00--2:59:59, 2:40 will be converted into UTC time in the
836         past.  So we will end up in this branch again, and may add
837         intervals in a 'do { } while' loop.
838 
839         Note that for any given event we may end up here only if event
840         next execution time will map to the time interval that is
841         passed twice, and only if the server was started during the
842         second pass, or the event is being created during the second
843         pass.  After that, we never will get here (unless we again
844         start the server during the second pass).  In other words,
845         such a condition is extremely rare.
846       */
847       interval.second= seconds;
848       do
849       {
850         next_time= add_interval(&local_start, time_zone,
851                                 INTERVAL_SECOND, interval);
852         if (next_time == 0)
853           goto done;
854       }
855       while (next_time <= time_now);
856     }
857   }
858   else
859   {
860     long diff_months= ((long) local_now.year - (long) local_start.year)*12 +
861                       ((long) local_now.month - (long) local_start.month);
862 
863     /*
864       Unlike for seconds above, the formula below returns the interval
865       that, when added to the local_start, will give the time in the
866       past, or somewhere in the current month.  We are interested in
867       the latter case, to see if this time has already passed, or is
868       yet to come this month.
869 
870       Note that the time is guaranteed to be in the past unless
871       (diff_months % months == 0), but no good optimization is
872       possible here, because (diff_months % months == 0) is what will
873       happen most of the time, as get_next_time() will be called right
874       after the execution of the event.  We could pass last_executed
875       time to this function, and see if the execution has already
876       happened this month, but for that we will have to convert
877       last_executed from seconds since epoch to local broken-down
878       time, and this will greatly reduce the effect of the
879       optimization.  So instead we keep the code simple and clean.
880     */
881     interval.month= (ulong) (diff_months - diff_months % months);
882     next_time= add_interval(&local_start, time_zone,
883                             INTERVAL_MONTH, interval);
884     if (next_time == 0)
885       goto done;
886 
887     if (next_time <= time_now)
888     {
889       interval.month= (ulong) months;
890       next_time= add_interval(&local_start, time_zone,
891                               INTERVAL_MONTH, interval);
892       if (next_time == 0)
893         goto done;
894     }
895   }
896 
897   DBUG_ASSERT(time_now < next_time);
898 
899   *next= next_time;
900 
901 done:
902   DBUG_PRINT("info", ("next_time: %ld", (long) next_time));
903   DBUG_RETURN(next_time == 0);
904 }
905 
906 
907 /*
908   Computes next execution time.
909 
910   SYNOPSIS
911     Event_queue_element::compute_next_execution_time()
912 
913   RETURN VALUE
914     FALSE  OK
915     TRUE   Error
916 
917   NOTES
918     The time is set in execute_at, if no more executions the latter is
919     set to 0.
920 */
921 
922 bool
923 Event_queue_element::compute_next_execution_time()
924 {
925   my_time_t time_now;
926   DBUG_ENTER("Event_queue_element::compute_next_execution_time");
927   DBUG_PRINT("enter", ("starts: %lu  ends: %lu  last_executed: %lu  this: %p",
928                        (long) starts, (long) ends, (long) last_executed,
929                        this));
930 
931   if (status != Event_parse_data::ENABLED)
932   {
933     DBUG_PRINT("compute_next_execution_time",
934                ("Event %s is DISABLED", name.str));
935     goto ret;
936   }
937   /* If one-time, no need to do computation */
938   if (!expression)
939   {
940     /* Let's check whether it was executed */
941     if (last_executed)
942     {
943       DBUG_PRINT("info",("One-time event %s.%s of was already executed",
944                          dbname.str, name.str));
945       dropped= (on_completion == Event_parse_data::ON_COMPLETION_DROP);
946       DBUG_PRINT("info",("One-time event will be dropped: %d.", dropped));
947 
948       status= Event_parse_data::DISABLED;
949     }
950     goto ret;
951   }
952 
953   time_now= current_thd->query_start();
954 
955   DBUG_PRINT("info",("NOW: [%lu]", (ulong) time_now));
956 
957   /* if time_now is after ends don't execute anymore */
958   if (!ends_null && ends < time_now)
959   {
960     DBUG_PRINT("info", ("NOW after ENDS, don't execute anymore"));
961     /* time_now is after ends. don't execute anymore */
962     execute_at= 0;
963     execute_at_null= TRUE;
964     if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
965       dropped= TRUE;
966     DBUG_PRINT("info", ("Dropped: %d", dropped));
967     status= Event_parse_data::DISABLED;
968 
969     goto ret;
970   }
971 
972   /*
973     Here time_now is before or equals ends if the latter is set.
974     Let's check whether time_now is before starts.
975     If so schedule for starts.
976   */
977   if (!starts_null && time_now <= starts)
978   {
979     if (time_now == starts && starts == last_executed)
980     {
981       /*
982         do nothing or we will schedule for second time execution at starts.
983       */
984     }
985     else
986     {
987       DBUG_PRINT("info", ("STARTS is future, NOW <= STARTS,sched for STARTS"));
988       /*
989         starts is in the future
990         time_now before starts. Scheduling for starts
991       */
992       execute_at= starts;
993       execute_at_null= FALSE;
994       goto ret;
995     }
996   }
997 
998   if (!starts_null && !ends_null)
999   {
1000     /*
1001       Both starts and m_ends are set and time_now is between them (incl.)
1002       If last_executed is set then increase with m_expression. The new MYSQL_TIME is
1003       after m_ends set execute_at to 0. And check for on_completion
1004       If not set then schedule for now.
1005     */
1006     DBUG_PRINT("info", ("Both STARTS & ENDS are set"));
1007     if (!last_executed)
1008     {
1009       DBUG_PRINT("info", ("Not executed so far."));
1010     }
1011 
1012     {
1013       my_time_t next_exec;
1014 
1015       if (get_next_time(time_zone, &next_exec, starts, time_now,
1016                         (int) expression, interval))
1017         goto err;
1018 
1019       /* There was previous execution */
1020       if (ends < next_exec)
1021       {
1022         DBUG_PRINT("info", ("Next execution of %s after ENDS. Stop executing.",
1023                    name.str));
1024         /* Next execution after ends. No more executions */
1025         execute_at= 0;
1026         execute_at_null= TRUE;
1027         if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
1028           dropped= TRUE;
1029         status= Event_parse_data::DISABLED;
1030       }
1031       else
1032       {
1033         DBUG_PRINT("info",("Next[%lu]", (ulong) next_exec));
1034         execute_at= next_exec;
1035         execute_at_null= FALSE;
1036       }
1037     }
1038     goto ret;
1039   }
1040   else if (starts_null && ends_null)
1041   {
1042     /* starts is always set, so this is a dead branch !! */
1043     DBUG_PRINT("info", ("Neither STARTS nor ENDS are set"));
1044     /*
1045       Both starts and m_ends are not set, so we schedule for the next
1046       based on last_executed.
1047     */
1048     if (last_executed)
1049     {
1050       my_time_t next_exec;
1051       if (get_next_time(time_zone, &next_exec, starts, time_now,
1052                         (int) expression, interval))
1053         goto err;
1054       execute_at= next_exec;
1055       DBUG_PRINT("info",("Next[%lu]", (ulong) next_exec));
1056     }
1057     else
1058     {
1059       /* last_executed not set. Schedule the event for now */
1060       DBUG_PRINT("info", ("Execute NOW"));
1061       execute_at= time_now;
1062     }
1063     execute_at_null= FALSE;
1064   }
1065   else
1066   {
1067     /* either starts or m_ends is set */
1068     if (!starts_null)
1069     {
1070       DBUG_PRINT("info", ("STARTS is set"));
1071       /*
1072         - starts is set.
1073         - starts is not in the future according to check made before
1074         Hence schedule for starts + m_expression in case last_executed
1075         is not set, otherwise to last_executed + m_expression
1076       */
1077       if (!last_executed)
1078       {
1079         DBUG_PRINT("info", ("Not executed so far."));
1080       }
1081 
1082       {
1083         my_time_t next_exec;
1084         if (get_next_time(time_zone, &next_exec, starts, time_now,
1085                           (int) expression, interval))
1086           goto err;
1087         execute_at= next_exec;
1088         DBUG_PRINT("info",("Next[%lu]", (ulong) next_exec));
1089       }
1090       execute_at_null= FALSE;
1091     }
1092     else
1093     {
1094       /* this is a dead branch, because starts is always set !!! */
1095       DBUG_PRINT("info", ("STARTS is not set. ENDS is set"));
1096       /*
1097         - m_ends is set
1098         - m_ends is after time_now or is equal
1099         Hence check for m_last_execute and increment with m_expression.
1100         If last_executed is not set then schedule for now
1101       */
1102 
1103       if (!last_executed)
1104         execute_at= time_now;
1105       else
1106       {
1107         my_time_t next_exec;
1108 
1109         if (get_next_time(time_zone, &next_exec, starts, time_now,
1110                           (int) expression, interval))
1111           goto err;
1112 
1113         if (ends < next_exec)
1114         {
1115           DBUG_PRINT("info", ("Next execution after ENDS. Stop executing."));
1116           execute_at= 0;
1117           execute_at_null= TRUE;
1118           status= Event_parse_data::DISABLED;
1119           if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
1120             dropped= TRUE;
1121         }
1122         else
1123         {
1124           DBUG_PRINT("info", ("Next[%lu]", (ulong) next_exec));
1125           execute_at= next_exec;
1126           execute_at_null= FALSE;
1127         }
1128       }
1129     }
1130     goto ret;
1131   }
1132 ret:
1133   DBUG_PRINT("info", ("ret: 0 execute_at: %lu", (long) execute_at));
1134   DBUG_RETURN(FALSE);
1135 err:
1136   DBUG_PRINT("info", ("ret=1"));
1137   DBUG_RETURN(TRUE);
1138 }
1139 
1140 
1141 /*
1142   Set the internal last_executed MYSQL_TIME struct to now. NOW is the
1143   time according to thd->query_start(), so the THD's clock.
1144 
1145   SYNOPSIS
1146     Event_queue_element::mark_last_executed()
1147       thd   thread context
1148 */
1149 
1150 void
1151 Event_queue_element::mark_last_executed(THD *thd)
1152 {
1153   last_executed= thd->query_start();
1154 
1155   execution_count++;
1156 }
1157 
1158 
1159 static
1160 void
1161 append_datetime(String *buf, Time_zone *time_zone, my_time_t secs,
1162                 const char *name, uint len)
1163 {
1164   char dtime_buff[20*2+32];/* +32 to make my_snprintf_{8bit|ucs2} happy */
1165   buf->append(STRING_WITH_LEN(" "));
1166   buf->append(name, len);
1167   buf->append(STRING_WITH_LEN(" '"));
1168   /*
1169     Pass the buffer and the second param tells fills the buffer and
1170     returns the number of chars to copy.
1171   */
1172   MYSQL_TIME time;
1173   time_zone->gmt_sec_to_TIME(&time, secs);
1174   buf->append(dtime_buff, my_datetime_to_str(&time, dtime_buff, 0));
1175   buf->append(STRING_WITH_LEN("'"));
1176 }
1177 
1178 
1179 /*
1180   Get SHOW CREATE EVENT as string
1181 
1182   SYNOPSIS
1183     Event_timed::get_create_event(THD *thd, String *buf)
1184       thd    Thread
1185       buf    String*, should be already allocated. CREATE EVENT goes inside.
1186 
1187   RETURN VALUE
1188     0                       OK
1189     EVEX_MICROSECOND_UNSUP  Error (for now if mysql.event has been
1190                             tampered and MICROSECONDS interval or
1191                             derivative has been put there.
1192 */
1193 
1194 int
1195 Event_timed::get_create_event(THD *thd, String *buf)
1196 {
1197   char tmp_buf[2 * STRING_BUFFER_USUAL_SIZE];
1198   String expr_buf(tmp_buf, sizeof(tmp_buf), system_charset_info);
1199   expr_buf.length(0);
1200 
1201   DBUG_ENTER("get_create_event");
1202   DBUG_PRINT("ret_info",("body_len=[%d]body=[%s]",
1203                          (int) body.length, body.str));
1204 
1205   if (expression && Events::reconstruct_interval_expression(&expr_buf, interval,
1206                                                             expression))
1207     DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
1208 
1209   buf->append(STRING_WITH_LEN("CREATE "));
1210   append_definer(thd, buf, &definer_user, &definer_host);
1211   buf->append(STRING_WITH_LEN("EVENT "));
1212   append_identifier(thd, buf, &name);
1213 
1214   if (expression)
1215   {
1216     buf->append(STRING_WITH_LEN(" ON SCHEDULE EVERY "));
1217     buf->append(expr_buf);
1218     buf->append(' ');
1219     LEX_CSTRING *ival= &interval_type_to_name[interval];
1220     buf->append(ival->str, ival->length);
1221 
1222     if (!starts_null)
1223       append_datetime(buf, time_zone, starts, STRING_WITH_LEN("STARTS"));
1224 
1225     if (!ends_null)
1226       append_datetime(buf, time_zone, ends, STRING_WITH_LEN("ENDS"));
1227   }
1228   else
1229   {
1230     append_datetime(buf, time_zone, execute_at,
1231                     STRING_WITH_LEN("ON SCHEDULE AT"));
1232   }
1233 
1234   if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
1235     buf->append(STRING_WITH_LEN(" ON COMPLETION NOT PRESERVE "));
1236   else
1237     buf->append(STRING_WITH_LEN(" ON COMPLETION PRESERVE "));
1238 
1239   if (status == Event_parse_data::ENABLED)
1240     buf->append(STRING_WITH_LEN("ENABLE"));
1241   else if (status == Event_parse_data::SLAVESIDE_DISABLED)
1242     buf->append(STRING_WITH_LEN("DISABLE ON SLAVE"));
1243   else
1244     buf->append(STRING_WITH_LEN("DISABLE"));
1245 
1246   if (comment.length)
1247   {
1248     buf->append(STRING_WITH_LEN(" COMMENT "));
1249     append_unescaped(buf, comment.str, comment.length);
1250   }
1251   buf->append(STRING_WITH_LEN(" DO "));
1252   buf->append(&body);
1253 
1254   DBUG_RETURN(0);
1255 }
1256 
1257 
1258 /**
1259   Get an artificial stored procedure to parse as an event definition.
1260 */
1261 
1262 bool
1263 Event_job_data::construct_sp_sql(THD *thd, String *sp_sql)
1264 {
1265   LEX_CSTRING buffer;
1266   const uint STATIC_SQL_LENGTH= 44;
1267 
1268   DBUG_ENTER("Event_job_data::construct_sp_sql");
1269 
1270   /*
1271     Allocate a large enough buffer on the thread execution memory
1272     root to avoid multiple [re]allocations on system heap
1273   */
1274   buffer.length= STATIC_SQL_LENGTH + name.length + body.length;
1275   if (! (buffer.str= (char*) thd->alloc(buffer.length)))
1276     DBUG_RETURN(TRUE);
1277 
1278   sp_sql->set(buffer.str, buffer.length, system_charset_info);
1279   sp_sql->length(0);
1280 
1281 
1282   sp_sql->append(STRING_WITH_LEN("CREATE "));
1283   sp_sql->append(STRING_WITH_LEN("PROCEDURE "));
1284   /*
1285     Let's use the same name as the event name to perhaps produce a
1286     better error message in case it is a part of some parse error.
1287     We're using append_identifier here to successfully parse
1288     events with reserved names.
1289   */
1290   append_identifier(thd, sp_sql, &name);
1291 
1292   /*
1293     The default SQL security of a stored procedure is DEFINER. We
1294     have already activated the security context of the event, so
1295     let's execute the procedure with the invoker rights to save on
1296     resets of security contexts.
1297   */
1298   sp_sql->append(STRING_WITH_LEN("() SQL SECURITY INVOKER "));
1299 
1300   if (thd->variables.sql_mode & MODE_ORACLE)
1301     sp_sql->append(STRING_WITH_LEN(" AS BEGIN "));
1302   sp_sql->append(&body);
1303   if (thd->variables.sql_mode & MODE_ORACLE)
1304     sp_sql->append(STRING_WITH_LEN("; END"));
1305 
1306   DBUG_RETURN(thd->is_fatal_error);
1307 }
1308 
1309 
1310 /**
1311   Get DROP EVENT statement to binlog the drop of ON COMPLETION NOT
1312   PRESERVE event.
1313 */
1314 
1315 bool
1316 Event_job_data::construct_drop_event_sql(THD *thd, String *sp_sql)
1317 {
1318   LEX_CSTRING buffer;
1319   const uint STATIC_SQL_LENGTH= 14;
1320 
1321   DBUG_ENTER("Event_job_data::construct_drop_event_sql");
1322 
1323   buffer.length= STATIC_SQL_LENGTH + name.length*2 + dbname.length*2;
1324   if (! (buffer.str= (char*) thd->alloc(buffer.length)))
1325     DBUG_RETURN(TRUE);
1326 
1327   sp_sql->set(buffer.str, buffer.length, system_charset_info);
1328   sp_sql->length(0);
1329 
1330   sp_sql->append(STRING_WITH_LEN("DROP EVENT "));
1331   append_identifier(thd, sp_sql, &dbname);
1332   sp_sql->append('.');
1333   append_identifier(thd, sp_sql, &name);
1334 
1335   DBUG_RETURN(thd->is_fatal_error);
1336 }
1337 
1338 /**
1339   Compiles and executes the event (the underlying sp_head object)
1340 
1341   @retval TRUE  error (reported to the error log)
1342   @retval FALSE success
1343 */
1344 
1345 bool
1346 Event_job_data::execute(THD *thd, bool drop)
1347 {
1348   String sp_sql;
1349 #ifndef NO_EMBEDDED_ACCESS_CHECKS
1350   Security_context event_sctx, *save_sctx= NULL;
1351 #endif
1352   List<Item> empty_item_list;
1353   bool ret= TRUE;
1354 
1355   DBUG_ENTER("Event_job_data::execute");
1356 
1357   thd->reset_for_next_command();
1358 
1359 #ifdef WITH_WSREP
1360   wsrep_open(thd);
1361   wsrep_before_command(thd);
1362 #endif /* WITH_WSREP */
1363   /*
1364     MySQL parser currently assumes that current database is either
1365     present in THD or all names in all statements are fully specified.
1366     And yet not fully specified names inside stored programs must be
1367     be supported, even if the current database is not set:
1368     CREATE PROCEDURE db1.p1() BEGIN CREATE TABLE t1; END//
1369     -- in this example t1 should be always created in db1 and the statement
1370     must parse even if there is no current database.
1371 
1372     To support this feature and still address the parser limitation,
1373     we need to set the current database here.
1374     We don't have to call mysql_change_db, since the checks performed
1375     in it are unnecessary for the purpose of parsing, and
1376     mysql_change_db will be invoked anyway later, to activate the
1377     procedure database before it's executed.
1378   */
1379   thd->set_db(&dbname);
1380 
1381   lex_start(thd);
1382 
1383 #ifndef NO_EMBEDDED_ACCESS_CHECKS
1384   if (event_sctx.change_security_context(thd,
1385                                          &definer_user, &definer_host,
1386                                          &dbname, &save_sctx))
1387   {
1388     sql_print_error("Event Scheduler: "
1389                     "[%s].[%s.%s] execution failed, "
1390                     "failed to authenticate the user.",
1391                     definer.str, dbname.str, name.str);
1392     goto end;
1393   }
1394 #endif
1395 
1396   if (check_access(thd, EVENT_ACL, dbname.str, NULL, NULL, 0, 0))
1397   {
1398     /*
1399       This aspect of behavior is defined in the worklog,
1400       and this is how triggers work too: if TRIGGER
1401       privilege is revoked from trigger definer,
1402       triggers are not executed.
1403     */
1404     sql_print_error("Event Scheduler: "
1405                     "[%s].[%s.%s] execution failed, "
1406                     "user no longer has EVENT privilege.",
1407                     definer.str, dbname.str, name.str);
1408     goto end;
1409   }
1410 
1411   /*
1412     Set up global thread attributes to reflect the properties of
1413     this Event. We can simply reset these instead of usual
1414     backup/restore employed in stored programs since we know that
1415     this is a top level statement and the worker thread is
1416     allocated exclusively to execute this event.
1417   */
1418 
1419   thd->variables.sql_mode= sql_mode;
1420   thd->variables.time_zone= time_zone;
1421 
1422   if (construct_sp_sql(thd, &sp_sql))
1423     goto end;
1424 
1425   thd->set_query(sp_sql.c_ptr_safe(), sp_sql.length());
1426 
1427   {
1428     Parser_state parser_state;
1429     if (parser_state.init(thd, thd->query(), thd->query_length()))
1430       goto end;
1431 
1432     if (parse_sql(thd, & parser_state, creation_ctx))
1433     {
1434       sql_print_error("Event Scheduler: "
1435                       "%serror during compilation of %s.%s",
1436                       thd->is_fatal_error ? "fatal " : "",
1437                       (const char *) dbname.str, (const char *) name.str);
1438       goto end;
1439     }
1440   }
1441 
1442   {
1443     sp_head *sphead= thd->lex->sphead;
1444 
1445     DBUG_ASSERT(sphead);
1446 
1447     sphead->m_flags|= sp_head::LOG_SLOW_STATEMENTS;
1448     sphead->m_flags|= sp_head::LOG_GENERAL_LOG;
1449 
1450     /*
1451       construct_sp_sql() + parse_sql() set suid to SP_IS_NOT_SUID,
1452       because we have the security context already set to the event
1453       definer here. See more comments in construct_sp_sql().
1454     */
1455     DBUG_ASSERT(sphead->suid() == SP_IS_NOT_SUID);
1456     sphead->m_sql_mode= sql_mode;
1457     sphead->set_creation_ctx(creation_ctx);
1458     sphead->optimize();
1459 
1460     ret= sphead->execute_procedure(thd, &empty_item_list);
1461     /*
1462       There is no pre-locking and therefore there should be no
1463       tables open and locked left after execute_procedure.
1464     */
1465   }
1466 
1467 end:
1468   if (drop && likely(!thd->is_fatal_error))
1469   {
1470     /*
1471       We must do it here since here we're under the right authentication
1472       ID of the event definer.
1473     */
1474     sql_print_information("Event Scheduler: Dropping %s.%s",
1475                           (const char *) dbname.str, (const char *) name.str);
1476     /*
1477       Construct a query for the binary log, to ensure the event is dropped
1478       on the slave
1479     */
1480     if (construct_drop_event_sql(thd, &sp_sql))
1481       ret= 1;
1482     else
1483     {
1484       ulong saved_master_access;
1485 
1486       thd->set_query(sp_sql.c_ptr_safe(), sp_sql.length());
1487 
1488       /*
1489         NOTE: even if we run in read-only mode, we should be able to lock
1490         the mysql.event table for writing. In order to achieve this, we
1491         should call mysql_lock_tables() under the super-user.
1492 
1493         Same goes for transaction access mode.
1494         Temporarily reset it to read-write.
1495       */
1496 
1497       saved_master_access= thd->security_ctx->master_access;
1498       thd->security_ctx->master_access |= SUPER_ACL;
1499       bool save_tx_read_only= thd->tx_read_only;
1500       thd->tx_read_only= false;
1501 
1502       /*
1503          This code is processing event execution and does not have client
1504          connection. Here, event execution will now execute a prepared
1505          DROP EVENT statement, but thd->lex->sql_command is set to
1506          SQLCOM_CREATE_PROCEDURE
1507          DROP EVENT will be logged in binlog, and we have to
1508          replicate it to make all nodes have consistent event definitions
1509          Wsrep DDL replication is triggered inside Events::drop_event(),
1510          and here we need to prepare the THD so that DDL replication is
1511          possible, essentially it requires setting sql_command to
1512          SQLCOMM_DROP_EVENT, we will switch sql_command for the duration
1513          of DDL replication only.
1514       */
1515       const enum_sql_command sql_command_save= thd->lex->sql_command;
1516       const bool sql_command_set= WSREP(thd);
1517 
1518       if (sql_command_set)
1519         thd->lex->sql_command = SQLCOM_DROP_EVENT;
1520 
1521       ret= Events::drop_event(thd, &dbname, &name, FALSE);
1522 
1523       if (sql_command_set)
1524       {
1525         WSREP_TO_ISOLATION_END;
1526         thd->lex->sql_command = sql_command_save;
1527       }
1528 
1529       thd->tx_read_only= save_tx_read_only;
1530       thd->security_ctx->master_access= saved_master_access;
1531     }
1532   }
1533 #ifndef NO_EMBEDDED_ACCESS_CHECKS
1534   if (save_sctx)
1535     event_sctx.restore_security_context(thd, save_sctx);
1536 #endif
1537 #ifdef WITH_WSREP
1538   wsrep_after_command_ignore_result(thd);
1539   wsrep_close(thd);
1540 #endif /* WITH_WSREP */
1541   thd->lex->unit.cleanup();
1542   thd->end_statement();
1543   thd->cleanup_after_query();
1544   /* Avoid races with SHOW PROCESSLIST */
1545   thd->reset_query();
1546 
1547   DBUG_PRINT("info", ("EXECUTED %s.%s  ret: %d", dbname.str, name.str, ret));
1548 
1549   DBUG_RETURN(ret);
1550 }
1551 
1552 
1553 /*
1554   Checks whether two events are in the same schema
1555 
1556   SYNOPSIS
1557     event_basic_db_equal()
1558       db  Schema
1559       et  Compare et->dbname to `db`
1560 
1561   RETURN VALUE
1562     TRUE   Equal
1563     FALSE  Not equal
1564 */
1565 
1566 bool
1567 event_basic_db_equal(const LEX_CSTRING *db, Event_basic *et)
1568 {
1569   return !sortcmp_lex_string(&et->dbname, db, system_charset_info);
1570 }
1571 
1572 
1573 /*
1574   Checks whether an event has equal `db` and `name`
1575 
1576   SYNOPSIS
1577     event_basic_identifier_equal()
1578       db   Schema
1579       name Name
1580       et   The event object
1581 
1582   RETURN VALUE
1583     TRUE   Equal
1584     FALSE  Not equal
1585 */
1586 
1587 bool
1588 event_basic_identifier_equal(const LEX_CSTRING *db, const LEX_CSTRING *name,
1589                              Event_basic *b)
1590 {
1591   return !sortcmp_lex_string(name, &b->name, system_charset_info) &&
1592          !sortcmp_lex_string(db, &b->dbname, system_charset_info);
1593 }
1594 
1595 /**
1596   @} (End of group Event_Scheduler)
1597 */
1598