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