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