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