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