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(&ltime, TIME_NO_ZERO_DATE)))
228     goto wrong_value;
229 
230   ltime_utc= TIME_to_timestamp(thd,&ltime,&not_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(&ltime, TIME_NO_ZERO_DATE)))
392     goto wrong_value;
393 
394   ltime_utc= TIME_to_timestamp(thd, &ltime, &not_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(&ltime, TIME_NO_ZERO_DATE)))
447     goto error_bad_params;
448 
449   ltime_utc= TIME_to_timestamp(thd, &ltime, &not_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