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