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,¬_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,¬_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,¬_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,¬_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, ¬_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, µsec_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