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