1
/* Copyright (C) 2004-2006 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
17
#include "mysql_priv.h"
19
#include "event_data_objects.h"
20
#include "event_db_repository.h"
24
@addtogroup Event_Scheduler
28
/*************************************************************************/
31
Event_creation_ctx -- creation context of events.
34
class Event_creation_ctx :public Stored_program_creation_ctx,
38
static bool load_from_db(THD *thd,
39
MEM_ROOT *event_mem_root,
41
const char *event_name,
43
Stored_program_creation_ctx **ctx);
46
virtual Stored_program_creation_ctx *clone(MEM_ROOT *mem_root)
49
Event_creation_ctx(m_client_cs, m_connection_cl, m_db_cl);
53
virtual Object_creation_ctx *create_backup_ctx(THD *thd) const
56
We can avoid usual backup/restore employed in stored programs since we
57
know that this is a top level statement and the worker thread is
58
allocated exclusively to execute this event.
65
Event_creation_ctx(CHARSET_INFO *client_cs,
66
CHARSET_INFO *connection_cl,
68
: Stored_program_creation_ctx(client_cs, connection_cl, db_cl)
72
/**************************************************************************
73
Event_creation_ctx implementation.
74
**************************************************************************/
77
Event_creation_ctx::load_from_db(THD *thd,
78
MEM_ROOT *event_mem_root,
80
const char *event_name,
82
Stored_program_creation_ctx **ctx)
84
/* Load character set/collation attributes. */
86
CHARSET_INFO *client_cs;
87
CHARSET_INFO *connection_cl;
90
bool invalid_creation_ctx= FALSE;
92
if (load_charset(event_mem_root,
93
event_tbl->field[ET_FIELD_CHARACTER_SET_CLIENT],
94
thd->variables.character_set_client,
97
sql_print_warning("Event '%s'.'%s': invalid value "
98
"in column mysql.event.character_set_client.",
99
(const char *) db_name,
100
(const char *) event_name);
102
invalid_creation_ctx= TRUE;
105
if (load_collation(event_mem_root,
106
event_tbl->field[ET_FIELD_COLLATION_CONNECTION],
107
thd->variables.collation_connection,
110
sql_print_warning("Event '%s'.'%s': invalid value "
111
"in column mysql.event.collation_connection.",
112
(const char *) db_name,
113
(const char *) event_name);
115
invalid_creation_ctx= TRUE;
118
if (load_collation(event_mem_root,
119
event_tbl->field[ET_FIELD_DB_COLLATION],
123
sql_print_warning("Event '%s'.'%s': invalid value "
124
"in column mysql.event.db_collation.",
125
(const char *) db_name,
126
(const char *) event_name);
128
invalid_creation_ctx= TRUE;
132
If we failed to resolve the database collation, load the default one
137
db_cl= get_default_db_collation(thd, db_name);
139
/* Create the context. */
141
*ctx= new Event_creation_ctx(client_cs, connection_cl, db_cl);
143
return invalid_creation_ctx;
146
/*************************************************************************/
149
Initiliazes dbname and name of an Event_queue_element_for_exec
153
Event_queue_element_for_exec::init()
161
Event_queue_element_for_exec::init(LEX_STRING db, LEX_STRING n)
163
if (!(dbname.str= my_strndup(db.str, dbname.length= db.length, MYF(MY_WME))))
165
if (!(name.str= my_strndup(n.str, name.length= n.length, MYF(MY_WME))))
167
my_free((uchar*) dbname.str, MYF(0));
178
Event_queue_element_for_exec::~Event_queue_element_for_exec()
181
Event_queue_element_for_exec::~Event_queue_element_for_exec()
183
my_free((uchar*) dbname.str, MYF(0));
184
my_free((uchar*) name.str, MYF(0));
192
Event_basic::Event_basic()
195
Event_basic::Event_basic()
197
DBUG_ENTER("Event_basic::Event_basic");
198
/* init memory root */
199
init_alloc_root(&mem_root, 256, 512);
200
dbname.str= name.str= NULL;
201
dbname.length= name.length= 0;
211
Event_basic::Event_basic()
214
Event_basic::~Event_basic()
216
DBUG_ENTER("Event_basic::~Event_basic");
217
free_root(&mem_root, MYF(0));
223
Short function to load a char column into a LEX_STRING
226
Event_basic::load_string_field()
227
field_name The field( enum_events_table_field is not actually used
228
because it's unknown in event_data_objects.h)
229
fields The Field array
230
field_value The value
234
Event_basic::load_string_fields(Field **fields, ...)
238
enum enum_events_table_field field_name;
239
LEX_STRING *field_value;
241
DBUG_ENTER("Event_basic::load_string_fields");
243
va_start(args, fields);
244
field_name= (enum enum_events_table_field) va_arg(args, int);
245
while (field_name < ET_FIELD_COUNT)
247
field_value= va_arg(args, LEX_STRING *);
248
if ((field_value->str= get_field(&mem_root, fields[field_name])) == NullS)
253
field_value->length= strlen(field_value->str);
255
field_name= (enum enum_events_table_field) va_arg(args, int);
264
Event_basic::load_time_zone(THD *thd, const LEX_STRING tz_name)
266
String str(tz_name.str, &my_charset_latin1);
267
time_zone= my_tz_find(thd, &str);
269
return (time_zone == NULL);
277
Event_queue_element::Event_queue_element()
280
Event_queue_element::Event_queue_element():
281
status_changed(FALSE), last_executed_changed(FALSE),
282
on_completion(Event_parse_data::ON_COMPLETION_DROP),
283
status(Event_parse_data::ENABLED), expression(0), dropped(FALSE),
286
DBUG_ENTER("Event_queue_element::Event_queue_element");
288
starts= ends= execute_at= last_executed= 0;
289
starts_null= ends_null= execute_at_null= TRUE;
299
Event_queue_element::Event_queue_element()
301
Event_queue_element::~Event_queue_element()
310
Event_timed::Event_timed()
313
Event_timed::Event_timed():
314
created(0), modified(0), sql_mode(0)
316
DBUG_ENTER("Event_timed::Event_timed");
326
Event_timed::~Event_timed()
329
Event_timed::~Event_timed()
338
Event_job_data::Event_job_data()
341
Event_job_data::Event_job_data()
347
Init all member variables
356
DBUG_ENTER("Event_timed::init");
358
definer_user.str= definer_host.str= body.str= comment.str= NULL;
359
definer_user.length= definer_host.length= body.length= comment.length= 0;
368
Load an event's body from a row from mysql.event.
370
@details This method is silent on errors and should behave like that.
371
Callers should handle throwing of error messages. The reason is that the
372
class should not know about how to deal with communication.
374
@return Operation status
380
Event_job_data::load_from_row(THD *thd, TABLE *table)
386
DBUG_ENTER("Event_job_data::load_from_row");
391
if (table->s->fields < ET_FIELD_COUNT)
394
if (load_string_fields(table->field,
395
ET_FIELD_DB, &dbname,
396
ET_FIELD_NAME, &name,
397
ET_FIELD_BODY, &body,
398
ET_FIELD_DEFINER, &definer,
399
ET_FIELD_TIME_ZONE, &tz_name,
403
if (load_time_zone(thd, tz_name))
406
Event_creation_ctx::load_from_db(thd, &mem_root, dbname.str, name.str, table,
409
ptr= strchr(definer.str, '@');
414
len= ptr - definer.str;
415
definer_user.str= strmake_root(&mem_root, definer.str, len);
416
definer_user.length= len;
417
len= definer.length - len - 1;
419
definer_host.str= strmake_root(&mem_root, ptr + 1, len);
420
definer_host.length= len;
422
sql_mode= (ulong) table->field[ET_FIELD_SQL_MODE]->val_int();
429
Load an event's body from a row from mysql.event.
431
@details This method is silent on errors and should behave like that.
432
Callers should handle throwing of error messages. The reason is that the
433
class should not know about how to deal with communication.
435
@return Operation status
441
Event_queue_element::load_from_row(THD *thd, TABLE *table)
447
DBUG_ENTER("Event_queue_element::load_from_row");
452
if (table->s->fields < ET_FIELD_COUNT)
455
if (load_string_fields(table->field,
456
ET_FIELD_DB, &dbname,
457
ET_FIELD_NAME, &name,
458
ET_FIELD_DEFINER, &definer,
459
ET_FIELD_TIME_ZONE, &tz_name,
463
if (load_time_zone(thd, tz_name))
466
starts_null= table->field[ET_FIELD_STARTS]->is_null();
467
my_bool not_used= FALSE;
470
table->field[ET_FIELD_STARTS]->get_date(&time, TIME_NO_ZERO_DATE);
471
starts= my_tz_OFFSET0->TIME_to_gmt_sec(&time,¬_used);
474
ends_null= table->field[ET_FIELD_ENDS]->is_null();
477
table->field[ET_FIELD_ENDS]->get_date(&time, TIME_NO_ZERO_DATE);
478
ends= my_tz_OFFSET0->TIME_to_gmt_sec(&time,¬_used);
481
if (!table->field[ET_FIELD_INTERVAL_EXPR]->is_null())
482
expression= table->field[ET_FIELD_INTERVAL_EXPR]->val_int();
486
If neigher STARTS and ENDS is set, then both fields are empty.
487
Hence, if ET_FIELD_EXECUTE_AT is empty there is an error.
489
execute_at_null= table->field[ET_FIELD_EXECUTE_AT]->is_null();
490
DBUG_ASSERT(!(starts_null && ends_null && !expression && execute_at_null));
491
if (!expression && !execute_at_null)
493
if (table->field[ET_FIELD_EXECUTE_AT]->get_date(&time,
496
execute_at= my_tz_OFFSET0->TIME_to_gmt_sec(&time,¬_used);
500
We load the interval type from disk as string and then map it to
501
an integer. This decouples the values of enum interval_type
502
and values actually stored on disk. Therefore the type can be
503
reordered without risking incompatibilities of data between versions.
505
if (!table->field[ET_FIELD_TRANSIENT_INTERVAL]->is_null())
508
char buff[MAX_FIELD_WIDTH];
509
String str(buff, sizeof(buff), &my_charset_bin);
512
table->field[ET_FIELD_TRANSIENT_INTERVAL]->val_str(&str);
513
if (!(tmp.length= str.length()))
516
tmp.str= str.c_ptr_safe();
518
i= find_string_in_array(interval_type_to_name, &tmp, system_charset_info);
521
interval= (interval_type) i;
524
if (!table->field[ET_FIELD_LAST_EXECUTED]->is_null())
526
table->field[ET_FIELD_LAST_EXECUTED]->get_date(&time,
528
last_executed= my_tz_OFFSET0->TIME_to_gmt_sec(&time,¬_used);
530
last_executed_changed= FALSE;
532
if ((ptr= get_field(&mem_root, table->field[ET_FIELD_STATUS])) == NullS)
535
DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", name.str, ptr));
537
/* Set event status (ENABLED | SLAVESIDE_DISABLED | DISABLED) */
541
status = Event_parse_data::ENABLED;
544
status = Event_parse_data::SLAVESIDE_DISABLED;
548
status = Event_parse_data::DISABLED;
551
if ((ptr= get_field(&mem_root, table->field[ET_FIELD_ORIGINATOR])) == NullS)
553
originator = table->field[ET_FIELD_ORIGINATOR]->val_int();
555
/* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
556
if ((ptr= get_field(&mem_root,
557
table->field[ET_FIELD_ON_COMPLETION])) == NullS)
560
on_completion= (ptr[0]=='D'? Event_parse_data::ON_COMPLETION_DROP:
561
Event_parse_data::ON_COMPLETION_PRESERVE);
568
Load an event's body from a row from mysql.event.
570
@details This method is silent on errors and should behave like that.
571
Callers should handle throwing of error messages. The reason is that the
572
class should not know about how to deal with communication.
574
@return Operation status
580
Event_timed::load_from_row(THD *thd, TABLE *table)
585
DBUG_ENTER("Event_timed::load_from_row");
587
if (Event_queue_element::load_from_row(thd, table))
590
if (load_string_fields(table->field,
591
ET_FIELD_BODY, &body,
592
ET_FIELD_BODY_UTF8, &body_utf8,
596
if (Event_creation_ctx::load_from_db(thd, &mem_root, dbname.str, name.str,
597
table, &creation_ctx))
599
push_warning_printf(thd,
600
MYSQL_ERROR::WARN_LEVEL_WARN,
601
ER_EVENT_INVALID_CREATION_CTX,
602
ER(ER_EVENT_INVALID_CREATION_CTX),
603
(const char *) dbname.str,
604
(const char *) name.str);
607
ptr= strchr(definer.str, '@');
612
len= ptr - definer.str;
613
definer_user.str= strmake_root(&mem_root, definer.str, len);
614
definer_user.length= len;
615
len= definer.length - len - 1;
617
definer_host.str= strmake_root(&mem_root, ptr + 1, len);
618
definer_host.length= len;
620
created= table->field[ET_FIELD_CREATED]->val_int();
621
modified= table->field[ET_FIELD_MODIFIED]->val_int();
623
comment.str= get_field(&mem_root, table->field[ET_FIELD_COMMENT]);
624
if (comment.str != NullS)
625
comment.length= strlen(comment.str);
629
sql_mode= (ulong) table->field[ET_FIELD_SQL_MODE]->val_int();
636
add_interval() adds a specified interval to time 'ltime' in time
637
zone 'time_zone', and returns the result converted to the number of
638
seconds since epoch (aka Unix time; in UTC time zone). Zero result
643
add_interval(MYSQL_TIME *ltime, const Time_zone *time_zone,
644
interval_type scale, INTERVAL interval)
646
if (date_add_interval(ltime, scale, interval))
650
return time_zone->TIME_to_gmt_sec(ltime, ¬_used);
655
Computes the sum of a timestamp plus interval.
659
time_zone event time zone
661
start add interval_value to this time
662
time_now current time
663
i_value quantity of time type interval to add
664
i_type type of interval to add (SECOND, MINUTE, HOUR, WEEK ...)
671
1) If the interval is conversible to SECOND, like MINUTE, HOUR, DAY, WEEK.
672
Then we use TIMEDIFF()'s implementation as underlying and number of
673
seconds as resolution for computation.
674
2) In all other cases - MONTH, QUARTER, YEAR we use MONTH as resolution
675
and PERIOD_DIFF()'s implementation
679
bool get_next_time(const Time_zone *time_zone, my_time_t *next,
680
my_time_t start, my_time_t time_now,
681
int i_value, interval_type i_type)
683
DBUG_ENTER("get_next_time");
684
DBUG_PRINT("enter", ("start: %lu now: %lu", (long) start, (long) time_now));
686
DBUG_ASSERT(start <= time_now);
688
longlong months=0, seconds=0;
694
case INTERVAL_QUARTER:
695
/* Has already been converted to months */
696
case INTERVAL_YEAR_MONTH:
701
/* WEEK has already been converted to days */
703
seconds= i_value*24*3600;
705
case INTERVAL_DAY_HOUR:
707
seconds= i_value*3600;
709
case INTERVAL_DAY_MINUTE:
710
case INTERVAL_HOUR_MINUTE:
711
case INTERVAL_MINUTE:
714
case INTERVAL_DAY_SECOND:
715
case INTERVAL_HOUR_SECOND:
716
case INTERVAL_MINUTE_SECOND:
717
case INTERVAL_SECOND:
720
case INTERVAL_DAY_MICROSECOND:
721
case INTERVAL_HOUR_MICROSECOND:
722
case INTERVAL_MINUTE_MICROSECOND:
723
case INTERVAL_SECOND_MICROSECOND:
724
case INTERVAL_MICROSECOND:
726
We should return an error here so SHOW EVENTS/ SELECT FROM I_S.EVENTS
727
would give an error then.
734
DBUG_PRINT("info", ("seconds: %ld months: %ld", (long) seconds, (long) months));
736
MYSQL_TIME local_start;
737
MYSQL_TIME local_now;
739
/* Convert times from UTC to local. */
741
time_zone->gmt_sec_to_TIME(&local_start, start);
742
time_zone->gmt_sec_to_TIME(&local_now, time_now);
746
bzero(&interval, sizeof(interval));
747
my_time_t next_time= 0;
751
longlong seconds_diff;
753
bool negative= calc_time_diff(&local_now, &local_start, 1,
754
&seconds_diff, µsec_diff);
758
The formula below returns the interval that, when added to
759
local_start, will always give the time in the future.
761
interval.second= seconds_diff - seconds_diff % seconds + seconds;
762
next_time= add_interval(&local_start, time_zone,
763
INTERVAL_SECOND, interval);
768
if (next_time <= time_now)
771
If 'negative' is true above, then 'next_time == 0', and
772
'next_time <= time_now' is also true. If negative is false,
773
then next_time was set, but perhaps to the value that is less
774
then time_now. See below for elaboration.
776
DBUG_ASSERT(negative || next_time > 0);
779
If local_now < local_start, i.e. STARTS time is in the future
780
according to the local time (it always in the past according
781
to UTC---this is a prerequisite of this function), then
782
STARTS is almost always in the past according to the local
783
time too. However, in the time zone that has backward
784
Daylight Saving Time shift, the following may happen: suppose
785
we have a backward DST shift at certain date after 2:59:59,
786
i.e. local time goes 1:59:59, 2:00:00, ... , 2:59:59, (shift
787
here) 2:00:00 (again), ... , 2:59:59 (again), 3:00:00, ... .
788
Now suppose the time has passed the first 2:59:59, has been
789
shifted backward, and now is (the second) 2:20:00. The user
790
does CREATE EVENT with STARTS 'current-date 2:40:00'. Local
791
time 2:40:00 from create statement is treated by time
792
functions as the first such time, so according to UTC it comes
793
before the second 2:20:00. But according to local time it is
794
obviously in the future, so we end up in this branch.
796
Since we are in the second pass through 2:00:00--2:59:59, and
797
any local time form this interval is treated by system
798
functions as the time from the first pass, we have to find the
799
time for the next execution that is past the DST-affected
800
interval (past the second 2:59:59 for our example,
801
i.e. starting from 3:00:00). We do this in the loop until the
802
local time is mapped onto future UTC time. 'start' time is in
803
the past, so we may use 'do { } while' here, and add the first
806
Alternatively, it could be that local_now >= local_start. Now
807
for the example above imagine we do CREATE EVENT with STARTS
808
'current-date 2:10:00'. Local start 2:10 is in the past (now
809
is local 2:20), so we add an interval, and get next execution
810
time, say, 2:40. It is in the future according to local time,
811
but, again, since we are in the second pass through
812
2:00:00--2:59:59, 2:40 will be converted into UTC time in the
813
past. So we will end up in this branch again, and may add
814
intervals in a 'do { } while' loop.
816
Note that for any given event we may end up here only if event
817
next execution time will map to the time interval that is
818
passed twice, and only if the server was started during the
819
second pass, or the event is being created during the second
820
pass. After that, we never will get here (unless we again
821
start the server during the second pass). In other words,
822
such a condition is extremely rare.
824
interval.second= seconds;
827
next_time= add_interval(&local_start, time_zone,
828
INTERVAL_SECOND, interval);
832
while (next_time <= time_now);
837
long diff_months= (long) (local_now.year - local_start.year)*12 +
838
(local_now.month - local_start.month);
840
Unlike for seconds above, the formula below returns the interval
841
that, when added to the local_start, will give the time in the
842
past, or somewhere in the current month. We are interested in
843
the latter case, to see if this time has already passed, or is
844
yet to come this month.
846
Note that the time is guaranteed to be in the past unless
847
(diff_months % months == 0), but no good optimization is
848
possible here, because (diff_months % months == 0) is what will
849
happen most of the time, as get_next_time() will be called right
850
after the execution of the event. We could pass last_executed
851
time to this function, and see if the execution has already
852
happened this month, but for that we will have to convert
853
last_executed from seconds since epoch to local broken-down
854
time, and this will greatly reduce the effect of the
855
optimization. So instead we keep the code simple and clean.
857
interval.month= (ulong) (diff_months - diff_months % months);
858
next_time= add_interval(&local_start, time_zone,
859
INTERVAL_MONTH, interval);
863
if (next_time <= time_now)
865
interval.month= (ulong) months;
866
next_time= add_interval(&local_start, time_zone,
867
INTERVAL_MONTH, interval);
873
DBUG_ASSERT(time_now < next_time);
878
DBUG_PRINT("info", ("next_time: %ld", (long) next_time));
879
DBUG_RETURN(next_time == 0);
884
Computes next execution time.
887
Event_queue_element::compute_next_execution_time()
894
The time is set in execute_at, if no more executions the latter is
899
Event_queue_element::compute_next_execution_time()
902
DBUG_ENTER("Event_queue_element::compute_next_execution_time");
903
DBUG_PRINT("enter", ("starts: %lu ends: %lu last_executed: %lu this: 0x%lx",
904
(long) starts, (long) ends, (long) last_executed,
907
if (status != Event_parse_data::ENABLED)
909
DBUG_PRINT("compute_next_execution_time",
910
("Event %s is DISABLED", name.str));
913
/* If one-time, no need to do computation */
916
/* Let's check whether it was executed */
919
DBUG_PRINT("info",("One-time event %s.%s of was already executed",
920
dbname.str, name.str));
921
dropped= (on_completion == Event_parse_data::ON_COMPLETION_DROP);
922
DBUG_PRINT("info",("One-time event will be dropped: %d.", dropped));
924
status= Event_parse_data::DISABLED;
925
status_changed= TRUE;
930
time_now= (my_time_t) current_thd->query_start();
932
DBUG_PRINT("info",("NOW: [%lu]", (ulong) time_now));
934
/* if time_now is after ends don't execute anymore */
935
if (!ends_null && ends < time_now)
937
DBUG_PRINT("info", ("NOW after ENDS, don't execute anymore"));
938
/* time_now is after ends. don't execute anymore */
940
execute_at_null= TRUE;
941
if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
943
DBUG_PRINT("info", ("Dropped: %d", dropped));
944
status= Event_parse_data::DISABLED;
945
status_changed= TRUE;
951
Here time_now is before or equals ends if the latter is set.
952
Let's check whether time_now is before starts.
953
If so schedule for starts.
955
if (!starts_null && time_now <= starts)
957
if (time_now == starts && starts == last_executed)
960
do nothing or we will schedule for second time execution at starts.
965
DBUG_PRINT("info", ("STARTS is future, NOW <= STARTS,sched for STARTS"));
967
starts is in the future
968
time_now before starts. Scheduling for starts
971
execute_at_null= FALSE;
976
if (!starts_null && !ends_null)
979
Both starts and m_ends are set and time_now is between them (incl.)
980
If last_executed is set then increase with m_expression. The new MYSQL_TIME is
981
after m_ends set execute_at to 0. And check for on_completion
982
If not set then schedule for now.
984
DBUG_PRINT("info", ("Both STARTS & ENDS are set"));
987
DBUG_PRINT("info", ("Not executed so far."));
993
if (get_next_time(time_zone, &next_exec, starts, time_now,
994
(int) expression, interval))
997
/* There was previous execution */
998
if (ends < next_exec)
1000
DBUG_PRINT("info", ("Next execution of %s after ENDS. Stop executing.",
1002
/* Next execution after ends. No more executions */
1004
execute_at_null= TRUE;
1005
if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
1007
status= Event_parse_data::DISABLED;
1008
status_changed= TRUE;
1012
DBUG_PRINT("info",("Next[%lu]", (ulong) next_exec));
1013
execute_at= next_exec;
1014
execute_at_null= FALSE;
1019
else if (starts_null && ends_null)
1021
/* starts is always set, so this is a dead branch !! */
1022
DBUG_PRINT("info", ("Neither STARTS nor ENDS are set"));
1024
Both starts and m_ends are not set, so we schedule for the next
1025
based on last_executed.
1029
my_time_t next_exec;
1030
if (get_next_time(time_zone, &next_exec, starts, time_now,
1031
(int) expression, interval))
1033
execute_at= next_exec;
1034
DBUG_PRINT("info",("Next[%lu]", (ulong) next_exec));
1038
/* last_executed not set. Schedule the event for now */
1039
DBUG_PRINT("info", ("Execute NOW"));
1040
execute_at= time_now;
1042
execute_at_null= FALSE;
1046
/* either starts or m_ends is set */
1049
DBUG_PRINT("info", ("STARTS is set"));
1052
- starts is not in the future according to check made before
1053
Hence schedule for starts + m_expression in case last_executed
1054
is not set, otherwise to last_executed + m_expression
1058
DBUG_PRINT("info", ("Not executed so far."));
1062
my_time_t next_exec;
1063
if (get_next_time(time_zone, &next_exec, starts, time_now,
1064
(int) expression, interval))
1066
execute_at= next_exec;
1067
DBUG_PRINT("info",("Next[%lu]", (ulong) next_exec));
1069
execute_at_null= FALSE;
1073
/* this is a dead branch, because starts is always set !!! */
1074
DBUG_PRINT("info", ("STARTS is not set. ENDS is set"));
1077
- m_ends is after time_now or is equal
1078
Hence check for m_last_execute and increment with m_expression.
1079
If last_executed is not set then schedule for now
1083
execute_at= time_now;
1086
my_time_t next_exec;
1088
if (get_next_time(time_zone, &next_exec, starts, time_now,
1089
(int) expression, interval))
1092
if (ends < next_exec)
1094
DBUG_PRINT("info", ("Next execution after ENDS. Stop executing."));
1096
execute_at_null= TRUE;
1097
status= Event_parse_data::DISABLED;
1098
status_changed= TRUE;
1099
if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
1104
DBUG_PRINT("info", ("Next[%lu]", (ulong) next_exec));
1105
execute_at= next_exec;
1106
execute_at_null= FALSE;
1113
DBUG_PRINT("info", ("ret: 0 execute_at: %lu", (long) execute_at));
1116
DBUG_PRINT("info", ("ret=1"));
1122
Set the internal last_executed MYSQL_TIME struct to now. NOW is the
1123
time according to thd->query_start(), so the THD's clock.
1126
Event_queue_element::mark_last_executed()
1131
Event_queue_element::mark_last_executed(THD *thd)
1133
last_executed= (my_time_t) thd->query_start();
1134
last_executed_changed= TRUE;
1141
Saves status and last_executed_at to the disk if changed.
1144
Event_queue_element::update_timing_fields()
1145
thd - thread context
1149
TRUE Error while opening mysql.event for writing or during
1154
Event_queue_element::update_timing_fields(THD *thd)
1156
Event_db_repository *db_repository= Events::get_db_repository();
1159
DBUG_ENTER("Event_queue_element::update_timing_fields");
1161
DBUG_PRINT("enter", ("name: %*s", (int) name.length, name.str));
1163
/* No need to update if nothing has changed */
1164
if (!(status_changed || last_executed_changed))
1167
ret= db_repository->update_timing_fields_for_event(thd,
1169
last_executed_changed,
1172
(ulonglong) status);
1173
last_executed_changed= status_changed= FALSE;
1180
append_datetime(String *buf, Time_zone *time_zone, my_time_t secs,
1181
const char *name, uint len)
1183
char dtime_buff[20*2+32];/* +32 to make my_snprintf_{8bit|ucs2} happy */
1184
buf->append(STRING_WITH_LEN(" "));
1185
buf->append(name, len);
1186
buf->append(STRING_WITH_LEN(" '"));
1188
Pass the buffer and the second param tells fills the buffer and
1189
returns the number of chars to copy.
1192
time_zone->gmt_sec_to_TIME(&time, secs);
1193
buf->append(dtime_buff, my_datetime_to_str(&time, dtime_buff));
1194
buf->append(STRING_WITH_LEN("'"));
1199
Get SHOW CREATE EVENT as string
1202
Event_timed::get_create_event(THD *thd, String *buf)
1204
buf String*, should be already allocated. CREATE EVENT goes inside.
1208
EVEX_MICROSECOND_UNSUP Error (for now if mysql.event has been
1209
tampered and MICROSECONDS interval or
1210
derivative has been put there.
1214
Event_timed::get_create_event(THD *thd, String *buf)
1216
char tmp_buf[2 * STRING_BUFFER_USUAL_SIZE];
1217
String expr_buf(tmp_buf, sizeof(tmp_buf), system_charset_info);
1220
DBUG_ENTER("get_create_event");
1221
DBUG_PRINT("ret_info",("body_len=[%d]body=[%s]",
1222
(int) body.length, body.str));
1224
if (expression && Events::reconstruct_interval_expression(&expr_buf, interval,
1226
DBUG_RETURN(EVEX_MICROSECOND_UNSUP);
1228
buf->append(STRING_WITH_LEN("CREATE EVENT "));
1229
append_identifier(thd, buf, name.str, name.length);
1233
buf->append(STRING_WITH_LEN(" ON SCHEDULE EVERY "));
1234
buf->append(expr_buf);
1236
LEX_STRING *ival= &interval_type_to_name[interval];
1237
buf->append(ival->str, ival->length);
1240
append_datetime(buf, time_zone, starts, STRING_WITH_LEN("STARTS"));
1243
append_datetime(buf, time_zone, ends, STRING_WITH_LEN("ENDS"));
1247
append_datetime(buf, time_zone, execute_at,
1248
STRING_WITH_LEN("ON SCHEDULE AT"));
1251
if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
1252
buf->append(STRING_WITH_LEN(" ON COMPLETION NOT PRESERVE "));
1254
buf->append(STRING_WITH_LEN(" ON COMPLETION PRESERVE "));
1256
if (status == Event_parse_data::ENABLED)
1257
buf->append(STRING_WITH_LEN("ENABLE"));
1258
else if (status == Event_parse_data::SLAVESIDE_DISABLED)
1259
buf->append(STRING_WITH_LEN("DISABLE ON SLAVE"));
1261
buf->append(STRING_WITH_LEN("DISABLE"));
1265
buf->append(STRING_WITH_LEN(" COMMENT "));
1266
append_unescaped(buf, comment.str, comment.length);
1268
buf->append(STRING_WITH_LEN(" DO "));
1269
buf->append(body.str, body.length);
1276
Get an artificial stored procedure to parse as an event definition.
1280
Event_job_data::construct_sp_sql(THD *thd, String *sp_sql)
1283
const uint STATIC_SQL_LENGTH= 44;
1285
DBUG_ENTER("Event_job_data::construct_sp_sql");
1288
Allocate a large enough buffer on the thread execution memory
1289
root to avoid multiple [re]allocations on system heap
1291
buffer.length= STATIC_SQL_LENGTH + name.length + body.length;
1292
if (! (buffer.str= (char*) thd->alloc(buffer.length)))
1295
sp_sql->set(buffer.str, buffer.length, system_charset_info);
1299
sp_sql->append(C_STRING_WITH_LEN("CREATE "));
1300
sp_sql->append(C_STRING_WITH_LEN("PROCEDURE "));
1302
Let's use the same name as the event name to perhaps produce a
1303
better error message in case it is a part of some parse error.
1304
We're using append_identifier here to successfully parse
1305
events with reserved names.
1307
append_identifier(thd, sp_sql, name.str, name.length);
1310
The default SQL security of a stored procedure is DEFINER. We
1311
have already activated the security context of the event, so
1312
let's execute the procedure with the invoker rights to save on
1313
resets of security contexts.
1315
sp_sql->append(C_STRING_WITH_LEN("() SQL SECURITY INVOKER "));
1317
sp_sql->append(body.str, body.length);
1319
DBUG_RETURN(thd->is_fatal_error);
1324
Get DROP EVENT statement to binlog the drop of ON COMPLETION NOT
1329
Event_job_data::construct_drop_event_sql(THD *thd, String *sp_sql)
1332
const uint STATIC_SQL_LENGTH= 14;
1334
DBUG_ENTER("Event_job_data::construct_drop_event_sql");
1336
buffer.length= STATIC_SQL_LENGTH + name.length*2 + dbname.length*2;
1337
if (! (buffer.str= (char*) thd->alloc(buffer.length)))
1340
sp_sql->set(buffer.str, buffer.length, system_charset_info);
1343
sp_sql->append(C_STRING_WITH_LEN("DROP EVENT "));
1344
append_identifier(thd, sp_sql, dbname.str, dbname.length);
1345
sp_sql->append('.');
1346
append_identifier(thd, sp_sql, name.str, name.length);
1348
DBUG_RETURN(thd->is_fatal_error);
1352
Compiles and executes the event (the underlying sp_head object)
1354
@retval TRUE error (reported to the error log)
1355
@retval FALSE success
1359
Event_job_data::execute(THD *thd, bool drop)
1362
#ifndef NO_EMBEDDED_ACCESS_CHECKS
1363
Security_context event_sctx, *save_sctx= NULL;
1365
List<Item> empty_item_list;
1368
DBUG_ENTER("Event_job_data::execute");
1370
mysql_reset_thd_for_next_command(thd);
1373
MySQL parser currently assumes that current database is either
1374
present in THD or all names in all statements are fully specified.
1375
And yet not fully specified names inside stored programs must be
1376
be supported, even if the current database is not set:
1377
CREATE PROCEDURE db1.p1() BEGIN CREATE TABLE t1; END//
1378
-- in this example t1 should be always created in db1 and the statement
1379
must parse even if there is no current database.
1381
To support this feature and still address the parser limitation,
1382
we need to set the current database here.
1383
We don't have to call mysql_change_db, since the checks performed
1384
in it are unnecessary for the purpose of parsing, and
1385
mysql_change_db will be invoked anyway later, to activate the
1386
procedure database before it's executed.
1388
thd->set_db(dbname.str, dbname.length);
1390
#ifndef NO_EMBEDDED_ACCESS_CHECKS
1391
if (event_sctx.change_security_context(thd,
1392
&definer_user, &definer_host,
1393
&dbname, &save_sctx))
1395
sql_print_error("Event Scheduler: "
1396
"[%s].[%s.%s] execution failed, "
1397
"failed to authenticate the user.",
1398
definer.str, dbname.str, name.str);
1399
goto end_no_lex_start;
1403
if (check_access(thd, EVENT_ACL, dbname.str,
1404
0, 0, 0, is_schema_db(dbname.str, dbname.length)))
1407
This aspect of behavior is defined in the worklog,
1408
and this is how triggers work too: if TRIGGER
1409
privilege is revoked from trigger definer,
1410
triggers are not executed.
1412
sql_print_error("Event Scheduler: "
1413
"[%s].[%s.%s] execution failed, "
1414
"user no longer has EVENT privilege.",
1415
definer.str, dbname.str, name.str);
1416
goto end_no_lex_start;
1419
if (construct_sp_sql(thd, &sp_sql))
1420
goto end_no_lex_start;
1423
Set up global thread attributes to reflect the properties of
1424
this Event. We can simply reset these instead of usual
1425
backup/restore employed in stored programs since we know that
1426
this is a top level statement and the worker thread is
1427
allocated exclusively to execute this event.
1430
thd->variables.sql_mode= sql_mode;
1431
thd->variables.time_zone= time_zone;
1433
thd->set_query(sp_sql.c_ptr_safe(), sp_sql.length());
1436
Parser_state parser_state(thd, thd->query(), thd->query_length());
1439
if (parse_sql(thd, & parser_state, creation_ctx))
1441
sql_print_error("Event Scheduler: "
1442
"%serror during compilation of %s.%s",
1443
thd->is_fatal_error ? "fatal " : "",
1444
(const char *) dbname.str, (const char *) name.str);
1450
sp_head *sphead= thd->lex->sphead;
1452
DBUG_ASSERT(sphead);
1454
if (thd->enable_slow_log)
1455
sphead->m_flags|= sp_head::LOG_SLOW_STATEMENTS;
1456
sphead->m_flags|= sp_head::LOG_GENERAL_LOG;
1458
sphead->set_info(0, 0, &thd->lex->sp_chistics, sql_mode);
1459
sphead->set_creation_ctx(creation_ctx);
1462
ret= sphead->execute_procedure(thd, &empty_item_list);
1464
There is no pre-locking and therefore there should be no
1465
tables open and locked left after execute_procedure.
1470
if (thd->lex->sphead) /* NULL only if a parse error */
1472
delete thd->lex->sphead;
1473
thd->lex->sphead= NULL;
1477
if (drop && !thd->is_fatal_error)
1480
We must do it here since here we're under the right authentication
1481
ID of the event definer.
1483
sql_print_information("Event Scheduler: Dropping %s.%s",
1484
(const char *) dbname.str, (const char *) name.str);
1486
Construct a query for the binary log, to ensure the event is dropped
1489
if (construct_drop_event_sql(thd, &sp_sql))
1493
ulong saved_master_access;
1495
thd->set_query(sp_sql.c_ptr_safe(), sp_sql.length());
1498
NOTE: even if we run in read-only mode, we should be able to lock
1499
the mysql.event table for writing. In order to achieve this, we
1500
should call mysql_lock_tables() under the super-user.
1503
saved_master_access= thd->security_ctx->master_access;
1504
thd->security_ctx->master_access |= SUPER_ACL;
1506
ret= Events::drop_event(thd, dbname, name, FALSE);
1508
thd->security_ctx->master_access= saved_master_access;
1511
#ifndef NO_EMBEDDED_ACCESS_CHECKS
1513
event_sctx.restore_security_context(thd, save_sctx);
1516
thd->lex->unit.cleanup();
1517
thd->end_statement();
1518
thd->cleanup_after_query();
1519
/* Avoid races with SHOW PROCESSLIST */
1520
thd->set_query(NULL, 0);
1522
DBUG_PRINT("info", ("EXECUTED %s.%s ret: %d", dbname.str, name.str, ret));
1529
Checks whether two events are in the same schema
1532
event_basic_db_equal()
1534
et Compare et->dbname to `db`
1542
event_basic_db_equal(LEX_STRING db, Event_basic *et)
1544
return !sortcmp_lex_string(et->dbname, db, system_charset_info);
1549
Checks whether an event has equal `db` and `name`
1552
event_basic_identifier_equal()
1563
event_basic_identifier_equal(LEX_STRING db, LEX_STRING name, Event_basic *b)
1565
return !sortcmp_lex_string(name, b->name, system_charset_info) &&
1566
!sortcmp_lex_string(db, b->dbname, system_charset_info);
1570
@} (End of group Event_Scheduler)