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