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