1 /*
2 Copyright (c) 2008, 2021, 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, version 2.0,
6 as published by the Free Software Foundation.
7
8 This program is also distributed with certain software (including
9 but not limited to OpenSSL) that is licensed under separate terms,
10 as designated in a particular file or component or in included license
11 documentation. The authors of MySQL hereby grant you an additional
12 permission to link the program and your derivative works with the
13 separately licensed software that they have included with MySQL.
14
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 GNU General Public License, version 2.0, for more details.
19
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software Foundation,
22 51 Franklin Street, Suite 500, Boston, MA 02110-1335 USA */
23
24 #include "sp_head.h"
25 #include "event_parse_data.h"
26 #include "sql_time.h" // TIME_to_timestamp
27 #include "item_timefunc.h" // get_interval_value
28
29 /*
30 Returns a new instance
31
32 SYNOPSIS
33 Event_parse_data::new_instance()
34
35 RETURN VALUE
36 Address or NULL in case of error
37
38 NOTE
39 Created on THD's mem_root
40 */
41
42 Event_parse_data *
new_instance(THD * thd)43 Event_parse_data::new_instance(THD *thd)
44 {
45 return new (thd->mem_root) Event_parse_data;
46 }
47
48
49 /*
50 Constructor
51
52 SYNOPSIS
53 Event_parse_data::Event_parse_data()
54 */
55
Event_parse_data()56 Event_parse_data::Event_parse_data()
57 :on_completion(Event_parse_data::ON_COMPLETION_DEFAULT),
58 status(Event_parse_data::ENABLED), status_changed(false),
59 do_not_create(FALSE), body_changed(FALSE),
60 item_starts(NULL), item_ends(NULL), item_execute_at(NULL),
61 starts_null(TRUE), ends_null(TRUE), execute_at_null(TRUE),
62 item_expression(NULL), expression(0)
63 {
64 DBUG_ENTER("Event_parse_data::Event_parse_data");
65
66 /* Actually in the parser STARTS is always set */
67 starts= ends= execute_at= 0;
68
69 comment.str= NULL;
70 comment.length= 0;
71
72 DBUG_VOID_RETURN;
73 }
74
75
76 /*
77 Set a name of the event
78
79 SYNOPSIS
80 Event_parse_data::init_name()
81 thd THD
82 spn the name extracted in the parser
83 */
84
85 void
init_name(THD * thd,sp_name * spn)86 Event_parse_data::init_name(THD *thd, sp_name *spn)
87 {
88 DBUG_ENTER("Event_parse_data::init_name");
89
90 /* We have to copy strings to get them into the right memroot */
91 dbname.length= spn->m_db.length;
92 dbname.str= thd->strmake(spn->m_db.str, spn->m_db.length);
93 name.length= spn->m_name.length;
94 name.str= thd->strmake(spn->m_name.str, spn->m_name.length);
95
96 if (spn->m_qname.length == 0)
97 spn->init_qname(thd);
98
99 DBUG_VOID_RETURN;
100 }
101
102
103 /*
104 This function is called on CREATE EVENT or ALTER EVENT. When either
105 ENDS or AT is in the past, we are trying to create an event that
106 will never be executed. If it has ON COMPLETION NOT PRESERVE
107 (default), then it would normally be dropped already, so on CREATE
108 EVENT we give a warning, and do not create anyting. On ALTER EVENT
109 we give a error, and do not change the event.
110
111 If the event has ON COMPLETION PRESERVE, then we see if the event is
112 created or altered to the ENABLED (default) state. If so, then we
113 give a warning, and change the state to DISABLED.
114
115 Otherwise it is a valid event in ON COMPLETION PRESERVE DISABLE
116 state.
117 */
118
119 void
check_if_in_the_past(THD * thd,my_time_t ltime_utc)120 Event_parse_data::check_if_in_the_past(THD *thd, my_time_t ltime_utc)
121 {
122 if (ltime_utc >= (my_time_t) thd->query_start())
123 return;
124
125 /*
126 We'll come back later when we have the real on_completion value
127 */
128 if (on_completion == Event_parse_data::ON_COMPLETION_DEFAULT)
129 return;
130
131 if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
132 {
133 switch (thd->lex->sql_command) {
134 case SQLCOM_CREATE_EVENT:
135 push_warning(thd, Sql_condition::SL_NOTE,
136 ER_EVENT_CANNOT_CREATE_IN_THE_PAST,
137 ER(ER_EVENT_CANNOT_CREATE_IN_THE_PAST));
138 break;
139 case SQLCOM_ALTER_EVENT:
140 my_error(ER_EVENT_CANNOT_ALTER_IN_THE_PAST, MYF(0));
141 break;
142 default:
143 assert(0);
144 }
145
146 do_not_create= TRUE;
147 }
148 else if (status == Event_parse_data::ENABLED)
149 {
150 status= Event_parse_data::DISABLED;
151 status_changed= true;
152 push_warning(thd, Sql_condition::SL_NOTE,
153 ER_EVENT_EXEC_TIME_IN_THE_PAST,
154 ER(ER_EVENT_EXEC_TIME_IN_THE_PAST));
155 }
156 }
157
158
159 /*
160 Check time/dates in ALTER EVENT
161
162 We check whether ALTER EVENT was given dates that are in the past.
163 However to know how to react, we need the ON COMPLETION type. Hence,
164 the check is deferred until we have the previous ON COMPLETION type
165 from the event-db to fall back on if nothing was specified in the
166 ALTER EVENT-statement.
167
168 SYNOPSIS
169 Event_parse_data::check_dates()
170 thd Thread
171 on_completion ON COMPLETION value currently in event-db.
172 Will be overridden by value in ALTER EVENT if given.
173
174 RETURN VALUE
175 TRUE an error occurred, do not ALTER
176 FALSE OK
177 */
178
179 bool
check_dates(THD * thd,int previous_on_completion)180 Event_parse_data::check_dates(THD *thd, int previous_on_completion)
181 {
182 if (on_completion == Event_parse_data::ON_COMPLETION_DEFAULT)
183 {
184 on_completion= previous_on_completion;
185 if (!ends_null)
186 check_if_in_the_past(thd, ends);
187 if (!execute_at_null)
188 check_if_in_the_past(thd, execute_at);
189 }
190 return do_not_create;
191 }
192
193
194
195 /*
196 Sets time for execution for one-time event.
197
198 SYNOPSIS
199 Event_parse_data::init_execute_at()
200 thd Thread
201
202 RETURN VALUE
203 0 OK
204 ER_WRONG_VALUE Wrong value for execute at (reported)
205 */
206
207 int
init_execute_at(THD * thd)208 Event_parse_data::init_execute_at(THD *thd)
209 {
210 my_bool not_used;
211 MYSQL_TIME ltime;
212 my_time_t ltime_utc;
213
214 DBUG_ENTER("Event_parse_data::init_execute_at");
215
216 if (!item_execute_at)
217 DBUG_RETURN(0);
218
219 if (item_execute_at->fix_fields(thd, &item_execute_at))
220 goto wrong_value;
221
222 /* no starts and/or ends in case of execute_at */
223 DBUG_PRINT("info", ("starts_null && ends_null should be 1 is %d",
224 (starts_null && ends_null)));
225 assert(starts_null && ends_null);
226
227 if ((not_used= item_execute_at->get_date(<ime, TIME_NO_ZERO_DATE)))
228 goto wrong_value;
229
230 ltime_utc= TIME_to_timestamp(thd,<ime,¬_used);
231 if (!ltime_utc)
232 {
233 DBUG_PRINT("error", ("Execute AT after year 2037"));
234 goto wrong_value;
235 }
236
237 check_if_in_the_past(thd, ltime_utc);
238
239 execute_at_null= FALSE;
240 execute_at= ltime_utc;
241 DBUG_RETURN(0);
242
243 wrong_value:
244 report_bad_value("AT", item_execute_at);
245 DBUG_RETURN(ER_WRONG_VALUE);
246 }
247
248
249 /*
250 Sets time for execution of multi-time event.s
251
252 SYNOPSIS
253 Event_parse_data::init_interval()
254 thd Thread
255
256 RETURN VALUE
257 0 OK
258 EVEX_BAD_PARAMS Interval is not positive or MICROSECOND (reported)
259 ER_WRONG_VALUE Wrong value for interval (reported)
260 */
261
262 int
init_interval(THD * thd)263 Event_parse_data::init_interval(THD *thd)
264 {
265 String value;
266 Interval interval_tmp;
267
268 DBUG_ENTER("Event_parse_data::init_interval");
269 if (!item_expression)
270 DBUG_RETURN(0);
271
272 switch (interval) {
273 case INTERVAL_MINUTE_MICROSECOND:
274 case INTERVAL_HOUR_MICROSECOND:
275 case INTERVAL_DAY_MICROSECOND:
276 case INTERVAL_SECOND_MICROSECOND:
277 case INTERVAL_MICROSECOND:
278 my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND");
279 DBUG_RETURN(EVEX_BAD_PARAMS);
280 default:
281 break;
282 }
283
284 if (item_expression->fix_fields(thd, &item_expression))
285 goto wrong_value;
286
287 value.alloc(MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN);
288 if (get_interval_value(item_expression, interval, &value, &interval_tmp))
289 goto wrong_value;
290
291 expression= 0;
292
293 switch (interval) {
294 case INTERVAL_YEAR:
295 expression= interval_tmp.year;
296 break;
297 case INTERVAL_QUARTER:
298 case INTERVAL_MONTH:
299 expression= interval_tmp.month;
300 break;
301 case INTERVAL_WEEK:
302 case INTERVAL_DAY:
303 expression= interval_tmp.day;
304 break;
305 case INTERVAL_HOUR:
306 expression= interval_tmp.hour;
307 break;
308 case INTERVAL_MINUTE:
309 expression= interval_tmp.minute;
310 break;
311 case INTERVAL_SECOND:
312 expression= interval_tmp.second;
313 break;
314 case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM
315 expression= interval_tmp.year* 12 + interval_tmp.month;
316 break;
317 case INTERVAL_DAY_HOUR:
318 expression= interval_tmp.day* 24 + interval_tmp.hour;
319 break;
320 case INTERVAL_DAY_MINUTE:
321 expression= (interval_tmp.day* 24 + interval_tmp.hour) * 60 +
322 interval_tmp.minute;
323 break;
324 case INTERVAL_HOUR_SECOND: /* day is anyway 0 */
325 case INTERVAL_DAY_SECOND:
326 /* DAY_SECOND having problems because of leap seconds? */
327 expression= ((interval_tmp.day* 24 + interval_tmp.hour) * 60 +
328 interval_tmp.minute)*60
329 + interval_tmp.second;
330 break;
331 case INTERVAL_HOUR_MINUTE:
332 expression= interval_tmp.hour * 60 + interval_tmp.minute;
333 break;
334 case INTERVAL_MINUTE_SECOND:
335 expression= interval_tmp.minute * 60 + interval_tmp.second;
336 break;
337 case INTERVAL_LAST:
338 assert(0);
339 default:
340 ;/* these are the microsec stuff */
341 }
342 if (interval_tmp.neg || expression == 0 ||
343 expression > EVEX_MAX_INTERVAL_VALUE)
344 {
345 my_error(ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG, MYF(0));
346 DBUG_RETURN(EVEX_BAD_PARAMS);
347 }
348
349 DBUG_RETURN(0);
350
351 wrong_value:
352 report_bad_value("INTERVAL", item_expression);
353 DBUG_RETURN(ER_WRONG_VALUE);
354 }
355
356
357 /*
358 Sets STARTS.
359
360 SYNOPSIS
361 Event_parse_data::init_starts()
362 expr how much?
363
364 NOTES
365 Note that activation time is not execution time.
366 EVERY 5 MINUTE STARTS "2004-12-12 10:00:00" means that
367 the event will be executed every 5 minutes but this will
368 start at the date shown above. Expressions are possible :
369 DATE_ADD(NOW(), INTERVAL 1 DAY) -- start tommorow at
370 same time.
371
372 RETURN VALUE
373 0 OK
374 ER_WRONG_VALUE Starts before now
375 */
376
377 int
init_starts(THD * thd)378 Event_parse_data::init_starts(THD *thd)
379 {
380 my_bool not_used;
381 MYSQL_TIME ltime;
382 my_time_t ltime_utc;
383
384 DBUG_ENTER("Event_parse_data::init_starts");
385 if (!item_starts)
386 DBUG_RETURN(0);
387
388 if (item_starts->fix_fields(thd, &item_starts))
389 goto wrong_value;
390
391 if ((not_used= item_starts->get_date(<ime, TIME_NO_ZERO_DATE)))
392 goto wrong_value;
393
394 ltime_utc= TIME_to_timestamp(thd, <ime, ¬_used);
395 if (!ltime_utc)
396 goto wrong_value;
397
398 DBUG_PRINT("info",("now: %ld starts: %ld",
399 (long) thd->query_start(), (long) ltime_utc));
400
401 starts_null= FALSE;
402 starts= ltime_utc;
403 DBUG_RETURN(0);
404
405 wrong_value:
406 report_bad_value("STARTS", item_starts);
407 DBUG_RETURN(ER_WRONG_VALUE);
408 }
409
410
411 /*
412 Sets ENDS (deactivation time).
413
414 SYNOPSIS
415 Event_parse_data::init_ends()
416 thd THD
417
418 NOTES
419 Note that activation time is not execution time.
420 EVERY 5 MINUTE ENDS "2004-12-12 10:00:00" means that
421 the event will be executed every 5 minutes but this will
422 end at the date shown above. Expressions are possible :
423 DATE_ADD(NOW(), INTERVAL 1 DAY) -- end tommorow at
424 same time.
425
426 RETURN VALUE
427 0 OK
428 EVEX_BAD_PARAMS Error (reported)
429 */
430
431 int
init_ends(THD * thd)432 Event_parse_data::init_ends(THD *thd)
433 {
434 my_bool not_used;
435 MYSQL_TIME ltime;
436 my_time_t ltime_utc;
437
438 DBUG_ENTER("Event_parse_data::init_ends");
439 if (!item_ends)
440 DBUG_RETURN(0);
441
442 if (item_ends->fix_fields(thd, &item_ends))
443 goto error_bad_params;
444
445 DBUG_PRINT("info", ("convert to TIME"));
446 if ((not_used= item_ends->get_date(<ime, TIME_NO_ZERO_DATE)))
447 goto error_bad_params;
448
449 ltime_utc= TIME_to_timestamp(thd, <ime, ¬_used);
450 if (!ltime_utc)
451 goto error_bad_params;
452
453 /* Check whether ends is after starts */
454 DBUG_PRINT("info", ("ENDS after STARTS?"));
455 if (!starts_null && starts >= ltime_utc)
456 goto error_bad_params;
457
458 check_if_in_the_past(thd, ltime_utc);
459
460 ends_null= FALSE;
461 ends= ltime_utc;
462 DBUG_RETURN(0);
463
464 error_bad_params:
465 my_error(ER_EVENT_ENDS_BEFORE_STARTS, MYF(0));
466 DBUG_RETURN(EVEX_BAD_PARAMS);
467 }
468
469
470 /*
471 Prints an error message about invalid value. Internally used
472 during input data verification
473
474 SYNOPSIS
475 Event_parse_data::report_bad_value()
476 item_name The name of the parameter
477 bad_item The parameter
478 */
479
480 void
report_bad_value(const char * item_name,Item * bad_item)481 Event_parse_data::report_bad_value(const char *item_name, Item *bad_item)
482 {
483 char buff[120];
484 String str(buff, sizeof(buff), system_charset_info);
485 String *str2= bad_item->fixed? bad_item->val_str(&str):NULL;
486 my_error(ER_WRONG_VALUE, MYF(0), item_name, str2? str2->c_ptr_safe():"NULL");
487 }
488
489
490 /*
491 Checks for validity the data gathered during the parsing phase.
492
493 SYNOPSIS
494 Event_parse_data::check_parse_data()
495 thd Thread
496
497 RETURN VALUE
498 FALSE OK
499 TRUE Error (reported)
500 */
501
502 bool
check_parse_data(THD * thd)503 Event_parse_data::check_parse_data(THD *thd)
504 {
505 bool ret;
506 DBUG_ENTER("Event_parse_data::check_parse_data");
507 DBUG_PRINT("info", ("execute_at: 0x%lx expr=0x%lx starts=0x%lx ends=0x%lx",
508 (long) item_execute_at, (long) item_expression,
509 (long) item_starts, (long) item_ends));
510
511 init_name(thd, identifier);
512
513 init_definer(thd);
514
515 ret= init_execute_at(thd) || init_interval(thd) || init_starts(thd) ||
516 init_ends(thd);
517 check_originator_id(thd);
518 DBUG_RETURN(ret);
519 }
520
521
522 /*
523 Inits definer (definer_user and definer_host) during parsing.
524
525 SYNOPSIS
526 Event_parse_data::init_definer()
527 thd Thread
528 */
529
530 void
init_definer(THD * thd)531 Event_parse_data::init_definer(THD *thd)
532 {
533 DBUG_ENTER("Event_parse_data::init_definer");
534
535 assert(thd->lex->definer);
536
537 const char *definer_user= thd->lex->definer->user.str;
538 const char *definer_host= thd->lex->definer->host.str;
539 size_t definer_user_len= thd->lex->definer->user.length;
540 size_t definer_host_len= thd->lex->definer->host.length;
541
542 DBUG_PRINT("info",("init definer_user thd->mem_root: 0x%lx "
543 "definer_user: 0x%lx", (long) thd->mem_root,
544 (long) definer_user));
545
546 /* + 1 for @ */
547 DBUG_PRINT("info",("init definer as whole"));
548 definer.length= definer_user_len + definer_host_len + 1;
549 definer.str= (char*) thd->alloc(definer.length + 1);
550
551 DBUG_PRINT("info",("copy the user"));
552 memcpy(definer.str, definer_user, definer_user_len);
553 definer.str[definer_user_len]= '@';
554
555 DBUG_PRINT("info",("copy the host"));
556 memcpy(definer.str + definer_user_len + 1, definer_host, definer_host_len);
557 definer.str[definer.length]= '\0';
558 DBUG_PRINT("info",("definer [%s] initted", definer.str));
559
560 DBUG_VOID_RETURN;
561 }
562
563
564 /**
565 Set the originator id of the event to the server_id if executing on
566 the master or set to the server_id of the master if executing on
567 the slave. If executing on slave, also set status to SLAVESIDE_DISABLED.
568
569 SYNOPSIS
570 Event_parse_data::check_originator_id()
571 */
check_originator_id(THD * thd)572 void Event_parse_data::check_originator_id(THD *thd)
573 {
574 /* Disable replicated events on slave. */
575 if ((thd->system_thread == SYSTEM_THREAD_SLAVE_SQL) ||
576 (thd->system_thread == SYSTEM_THREAD_SLAVE_WORKER) ||
577 (thd->system_thread == SYSTEM_THREAD_SLAVE_IO))
578 {
579 DBUG_PRINT("info", ("Invoked object status set to SLAVESIDE_DISABLED."));
580 if ((status == Event_parse_data::ENABLED) ||
581 (status == Event_parse_data::DISABLED))
582 {
583 status= Event_parse_data::SLAVESIDE_DISABLED;
584 status_changed= true;
585 }
586 originator = thd->server_id;
587 }
588 else
589 originator = server_id;
590 }
591