1
/* Copyright 2004-2008 MySQL AB, 2008 Sun Microsystems, Inc.
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 */
16
#include "mysql_priv.h"
17
#include "event_db_repository.h"
19
#include "event_data_objects.h"
24
@addtogroup Event_Scheduler
29
const TABLE_FIELD_TYPE event_table_fields[ET_FIELD_COUNT] =
32
{ C_STRING_WITH_LEN("db") },
33
{ C_STRING_WITH_LEN("char(64)") },
34
{ C_STRING_WITH_LEN("utf8") }
37
{ C_STRING_WITH_LEN("name") },
38
{ C_STRING_WITH_LEN("char(64)") },
39
{ C_STRING_WITH_LEN("utf8") }
42
{ C_STRING_WITH_LEN("body") },
43
{ C_STRING_WITH_LEN("longblob") },
47
{ C_STRING_WITH_LEN("definer") },
48
{ C_STRING_WITH_LEN("char(77)") },
49
{ C_STRING_WITH_LEN("utf8") }
52
{ C_STRING_WITH_LEN("execute_at") },
53
{ C_STRING_WITH_LEN("datetime") },
57
{ C_STRING_WITH_LEN("interval_value") },
58
{ C_STRING_WITH_LEN("int(11)") },
62
{ C_STRING_WITH_LEN("interval_field") },
63
{ C_STRING_WITH_LEN("enum('YEAR','QUARTER','MONTH','DAY',"
64
"'HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR',"
65
"'DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND',"
66
"'DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND',"
67
"'SECOND_MICROSECOND')") },
71
{ C_STRING_WITH_LEN("created") },
72
{ C_STRING_WITH_LEN("timestamp") },
76
{ C_STRING_WITH_LEN("modified") },
77
{ C_STRING_WITH_LEN("timestamp") },
81
{ C_STRING_WITH_LEN("last_executed") },
82
{ C_STRING_WITH_LEN("datetime") },
86
{ C_STRING_WITH_LEN("starts") },
87
{ C_STRING_WITH_LEN("datetime") },
91
{ C_STRING_WITH_LEN("ends") },
92
{ C_STRING_WITH_LEN("datetime") },
96
{ C_STRING_WITH_LEN("status") },
97
{ C_STRING_WITH_LEN("enum('ENABLED','DISABLED','SLAVESIDE_DISABLED')") },
101
{ C_STRING_WITH_LEN("on_completion") },
102
{ C_STRING_WITH_LEN("enum('DROP','PRESERVE')") },
106
{ C_STRING_WITH_LEN("sql_mode") },
107
{ C_STRING_WITH_LEN("set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES',"
108
"'IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION',"
109
"'NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB',"
110
"'NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40',"
111
"'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES',"
112
"'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES',"
113
"'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER',"
114
"'HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH')") },
118
{ C_STRING_WITH_LEN("comment") },
119
{ C_STRING_WITH_LEN("char(64)") },
120
{ C_STRING_WITH_LEN("utf8") }
123
{ C_STRING_WITH_LEN("originator") },
124
{ C_STRING_WITH_LEN("int(10)") },
128
{ C_STRING_WITH_LEN("time_zone") },
129
{ C_STRING_WITH_LEN("char(64)") },
130
{ C_STRING_WITH_LEN("latin1") }
133
{ C_STRING_WITH_LEN("character_set_client") },
134
{ C_STRING_WITH_LEN("char(32)") },
135
{ C_STRING_WITH_LEN("utf8") }
138
{ C_STRING_WITH_LEN("collation_connection") },
139
{ C_STRING_WITH_LEN("char(32)") },
140
{ C_STRING_WITH_LEN("utf8") }
143
{ C_STRING_WITH_LEN("db_collation") },
144
{ C_STRING_WITH_LEN("char(32)") },
145
{ C_STRING_WITH_LEN("utf8") }
148
{ C_STRING_WITH_LEN("body_utf8") },
149
{ C_STRING_WITH_LEN("longblob") },
154
static const TABLE_FIELD_DEF
155
event_table_def= {ET_FIELD_COUNT, event_table_fields};
157
class Event_db_intact : public Table_check_intact
160
void report_error(uint, const char *fmt, ...)
164
error_log_print(ERROR_LEVEL, fmt, args);
169
/** In case of an error, a message is printed to the error log. */
170
static Event_db_intact table_intact;
174
Puts some data common to CREATE and ALTER EVENT into a row.
176
Used both when an event is created and when it is altered.
179
@param table The row to fill out
180
@param et Event's data
181
@param sp Event stored routine
182
@param is_update CREATE EVENT or ALTER EVENT
184
@retval FALSE success
189
mysql_event_fill_row(THD *thd,
191
Event_parse_data *et,
196
CHARSET_INFO *scs= system_charset_info;
197
enum enum_events_table_field f_num;
198
Field **fields= table->field;
201
DBUG_ENTER("mysql_event_fill_row");
203
DBUG_PRINT("info", ("dbname=[%s]", et->dbname.str));
204
DBUG_PRINT("info", ("name =[%s]", et->name.str));
206
DBUG_ASSERT(et->on_completion != Event_parse_data::ON_COMPLETION_DEFAULT);
208
if (table->s->fields < ET_FIELD_COUNT)
211
Safety: this can only happen if someone started the server
212
and then altered mysql.event.
214
my_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED, MYF(0), table->alias,
215
(int) ET_FIELD_COUNT, table->s->fields);
219
if (fields[f_num= ET_FIELD_DEFINER]->
220
store(et->definer.str, et->definer.length, scs))
223
if (fields[f_num= ET_FIELD_DB]->store(et->dbname.str, et->dbname.length, scs))
226
if (fields[f_num= ET_FIELD_NAME]->store(et->name.str, et->name.length, scs))
229
/* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()*/
230
rs|= fields[ET_FIELD_ON_COMPLETION]->store((longlong)et->on_completion, TRUE);
231
rs|= fields[ET_FIELD_STATUS]->store((longlong)et->status, TRUE);
232
rs|= fields[ET_FIELD_ORIGINATOR]->store((longlong)et->originator, TRUE);
235
Change the SQL_MODE only if body was present in an ALTER EVENT and of course
236
always during CREATE EVENT.
238
if (et->body_changed)
240
DBUG_ASSERT(sp->m_body.str);
242
rs|= fields[ET_FIELD_SQL_MODE]->store((longlong)sql_mode, TRUE);
244
if (fields[f_num= ET_FIELD_BODY]->store(sp->m_body.str,
254
const String *tz_name= thd->variables.time_zone->get_name();
255
if (!is_update || !et->starts_null)
257
fields[ET_FIELD_TIME_ZONE]->set_notnull();
258
rs|= fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(),
262
fields[ET_FIELD_INTERVAL_EXPR]->set_notnull();
263
rs|= fields[ET_FIELD_INTERVAL_EXPR]->store((longlong)et->expression, TRUE);
265
fields[ET_FIELD_TRANSIENT_INTERVAL]->set_notnull();
267
rs|= fields[ET_FIELD_TRANSIENT_INTERVAL]->
268
store(interval_type_to_name[et->interval].str,
269
interval_type_to_name[et->interval].length,
272
fields[ET_FIELD_EXECUTE_AT]->set_null();
274
if (!et->starts_null)
277
my_tz_OFFSET0->gmt_sec_to_TIME(&time, et->starts);
279
fields[ET_FIELD_STARTS]->set_notnull();
280
fields[ET_FIELD_STARTS]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
286
my_tz_OFFSET0->gmt_sec_to_TIME(&time, et->ends);
288
fields[ET_FIELD_ENDS]->set_notnull();
289
fields[ET_FIELD_ENDS]->store_time(&time, MYSQL_TIMESTAMP_DATETIME);
292
else if (et->execute_at)
294
const String *tz_name= thd->variables.time_zone->get_name();
295
fields[ET_FIELD_TIME_ZONE]->set_notnull();
296
rs|= fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(),
299
fields[ET_FIELD_INTERVAL_EXPR]->set_null();
300
fields[ET_FIELD_TRANSIENT_INTERVAL]->set_null();
301
fields[ET_FIELD_STARTS]->set_null();
302
fields[ET_FIELD_ENDS]->set_null();
305
my_tz_OFFSET0->gmt_sec_to_TIME(&time, et->execute_at);
307
fields[ET_FIELD_EXECUTE_AT]->set_notnull();
308
fields[ET_FIELD_EXECUTE_AT]->
309
store_time(&time, MYSQL_TIMESTAMP_DATETIME);
313
DBUG_ASSERT(is_update);
315
it is normal to be here when the action is update
316
this is an error if the action is create. something is borked
320
((Field_timestamp *)fields[ET_FIELD_MODIFIED])->set_time();
324
if (fields[f_num= ET_FIELD_COMMENT]->
325
store(et->comment.str, et->comment.length, scs))
329
fields[ET_FIELD_CHARACTER_SET_CLIENT]->set_notnull();
330
rs|= fields[ET_FIELD_CHARACTER_SET_CLIENT]->store(
331
thd->variables.character_set_client->csname,
332
strlen(thd->variables.character_set_client->csname),
333
system_charset_info);
335
fields[ET_FIELD_COLLATION_CONNECTION]->set_notnull();
336
rs|= fields[ET_FIELD_COLLATION_CONNECTION]->store(
337
thd->variables.collation_connection->name,
338
strlen(thd->variables.collation_connection->name),
339
system_charset_info);
342
CHARSET_INFO *db_cl= get_default_db_collation(thd, et->dbname.str);
344
fields[ET_FIELD_DB_COLLATION]->set_notnull();
345
rs|= fields[ET_FIELD_DB_COLLATION]->store(db_cl->name,
347
system_charset_info);
350
if (et->body_changed)
352
fields[ET_FIELD_BODY_UTF8]->set_notnull();
353
rs|= fields[ET_FIELD_BODY_UTF8]->store(sp->m_body_utf8.str,
354
sp->m_body_utf8.length,
355
system_charset_info);
360
my_error(ER_EVENT_STORE_FAILED, MYF(0), fields[f_num]->field_name, rs);
367
my_error(ER_EVENT_DATA_TOO_LONG, MYF(0), fields[f_num]->field_name);
373
Performs an index scan of event_table (mysql.event) and fills schema_table.
376
Event_db_repository::index_read_for_db_for_i_s()
378
schema_table The I_S.EVENTS table
379
event_table The event table to use for loading (mysql.event)
380
db For which schema to do an index scan.
388
Event_db_repository::index_read_for_db_for_i_s(THD *thd, TABLE *schema_table,
393
CHARSET_INFO *scs= system_charset_info;
396
uchar *key_buf= NULL;
399
DBUG_ENTER("Event_db_repository::index_read_for_db_for_i_s");
401
DBUG_PRINT("info", ("Using prefix scanning on PK"));
402
event_table->file->ha_index_init(0, 1);
403
key_info= event_table->key_info;
405
if (key_info->key_parts == 0 ||
406
key_info->key_part[0].field != event_table->field[ET_FIELD_DB])
408
/* Corrupted table: no index or index on a wrong column */
409
my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
414
event_table->field[ET_FIELD_DB]->store(db, strlen(db), scs);
415
key_len= key_info->key_part[0].store_length;
417
if (!(key_buf= (uchar *)alloc_root(thd->mem_root, key_len)))
419
/* Don't send error, it would be done by sql_alloc_error_handler() */
424
key_copy(key_buf, event_table->record[0], key_info, key_len);
425
if (!(ret= event_table->file->index_read_map(event_table->record[0], key_buf,
429
DBUG_PRINT("info",("Found rows. Let's retrieve them. ret=%d", ret));
432
ret= copy_event_to_schema_table(thd, schema_table, event_table);
434
ret= event_table->file->index_next_same(event_table->record[0],
438
DBUG_PRINT("info", ("Scan finished. ret=%d", ret));
440
/* ret is guaranteed to be != 0 */
441
if (ret == HA_ERR_END_OF_FILE || ret == HA_ERR_KEY_NOT_FOUND)
444
event_table->file->print_error(ret, MYF(0));
447
event_table->file->ha_index_end();
449
DBUG_RETURN(test(ret));
454
Performs a table scan of event_table (mysql.event) and fills schema_table.
457
Events_db_repository::table_scan_all_for_i_s()
459
schema_table The I_S.EVENTS in memory table
460
event_table The event table to use for loading.
468
Event_db_repository::table_scan_all_for_i_s(THD *thd, TABLE *schema_table,
472
READ_RECORD read_record_info;
473
DBUG_ENTER("Event_db_repository::table_scan_all_for_i_s");
475
init_read_record(&read_record_info, thd, event_table, NULL, 1, 0, FALSE);
478
rr_sequential, in read_record(), returns 137==HA_ERR_END_OF_FILE,
479
but rr_handle_error returns -1 for that reason. Thus, read_record()
480
returns -1 eventually.
484
ret= read_record_info.read_record(&read_record_info);
486
ret= copy_event_to_schema_table(thd, schema_table, event_table);
489
DBUG_PRINT("info", ("Scan finished. ret=%d", ret));
490
end_read_record(&read_record_info);
492
/* ret is guaranteed to be != 0 */
493
DBUG_RETURN(ret == -1? FALSE:TRUE);
498
Fills I_S.EVENTS with data loaded from mysql.event. Also used by
501
The reason we reset and backup open tables here is that this
502
function may be called from any query that accesses
503
INFORMATION_SCHEMA - including a query that is issued from
504
a pre-locked statement, one that already has open and locked
507
@retval FALSE success
512
Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *tables,
515
TABLE *schema_table= tables->table;
516
TABLE *event_table= NULL;
519
DBUG_ENTER("Event_db_repository::fill_schema_events");
520
DBUG_PRINT("info",("db=%s", db? db:"(null)"));
522
if (open_event_table(thd, TL_READ, &event_table))
526
1. SELECT I_S => use table scan. I_S.EVENTS does not guarantee order
527
thus we won't order it. OTOH, SHOW EVENTS will be
529
2. SHOW EVENTS => PRIMARY KEY with prefix scanning on (db)
530
Reasoning: Events are per schema, therefore a scan over an index
531
will save use from doing a table scan and comparing
532
every single row's `db` with the schema which we show.
535
ret= index_read_for_db_for_i_s(thd, schema_table, event_table, db);
537
ret= table_scan_all_for_i_s(thd, schema_table, event_table);
539
close_thread_tables(thd);
541
DBUG_PRINT("info", ("Return code=%d", ret));
547
Open mysql.event table for read.
549
It's assumed that the caller knows what they are doing:
550
- whether it was necessary to reset-and-backup the open tables state
551
- whether the requested lock does not lead to a deadlock
552
- whether this open mode would work under LOCK TABLES, or inside a
553
stored function or trigger.
555
Note that if the table can't be locked successfully this operation will
556
close it. Therefore it provides guarantee that it either opens and locks
557
table or fails without leaving any tables open.
559
@param[in] thd Thread context
560
@param[in] lock_type How to lock the table
561
@param[out] table We will store the open table here
563
@retval TRUE open and lock failed - an error message is pushed into the
565
@retval FALSE success
569
Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type,
573
DBUG_ENTER("Event_db_repository::open_event_table");
575
tables.init_one_table("mysql", "event", lock_type);
577
if (simple_open_n_lock_tables(thd, &tables))
579
close_thread_tables(thd);
583
*table= tables.table;
584
tables.table->use_all_columns();
590
Creates an event record in mysql.event table.
592
Creates an event. Relies on mysql_event_fill_row which is shared with
595
@pre All semantic checks must be performed outside. This function
596
only creates a record on disk.
597
@pre The thread handle has no open tables.
599
@param[in,out] thd THD
600
@param[in] parse_data Parsed event definition
601
@param[in] create_if_not TRUE if IF NOT EXISTS clause was provided
602
to CREATE EVENT statement
604
@retval FALSE success
609
Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
610
my_bool create_if_not)
614
sp_head *sp= thd->lex->sphead;
615
ulong saved_mode= thd->variables.sql_mode;
617
DBUG_ENTER("Event_db_repository::create_event");
619
DBUG_PRINT("info", ("open mysql.event for update"));
622
/* Reset sql_mode during data dictionary operations. */
623
thd->variables.sql_mode= 0;
625
if (open_event_table(thd, TL_WRITE, &table))
628
DBUG_PRINT("info", ("name: %.*s", (int) parse_data->name.length,
629
parse_data->name.str));
631
DBUG_PRINT("info", ("check existance of an event with the same name"));
632
if (!find_named_event(parse_data->dbname, parse_data->name, table))
636
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
637
ER_EVENT_ALREADY_EXISTS, ER(ER_EVENT_ALREADY_EXISTS),
638
parse_data->name.str);
642
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), parse_data->name.str);
646
DBUG_PRINT("info", ("non-existent, go forward"));
648
restore_record(table, s->default_values); // Get default values for fields
650
if (system_charset_info->cset->
651
numchars(system_charset_info, parse_data->dbname.str,
652
parse_data->dbname.str + parse_data->dbname.length) >
653
table->field[ET_FIELD_DB]->char_length())
655
my_error(ER_TOO_LONG_IDENT, MYF(0), parse_data->dbname.str);
659
if (system_charset_info->cset->
660
numchars(system_charset_info, parse_data->name.str,
661
parse_data->name.str + parse_data->name.length) >
662
table->field[ET_FIELD_NAME]->char_length())
664
my_error(ER_TOO_LONG_IDENT, MYF(0), parse_data->name.str);
668
if (sp->m_body.length > table->field[ET_FIELD_BODY]->field_length)
670
my_error(ER_TOO_LONG_BODY, MYF(0), parse_data->name.str);
674
((Field_timestamp *)table->field[ET_FIELD_CREATED])->set_time();
677
mysql_event_fill_row() calls my_error() in case of error so no need to
680
if (mysql_event_fill_row(thd, table, parse_data, sp, saved_mode, FALSE))
683
table->field[ET_FIELD_STATUS]->store((longlong)parse_data->status, TRUE);
685
if ((ret= table->file->ha_write_row(table->record[0])))
687
table->file->print_error(ret, MYF(0));
694
close_thread_tables(thd);
695
thd->variables.sql_mode= saved_mode;
696
DBUG_RETURN(test(ret));
701
Used to execute ALTER EVENT. Pendant to Events::update_event().
703
@param[in,out] thd thread handle
704
@param[in] parse_data parsed event definition
705
@param[in] new_dbname not NULL if ALTER EVENT RENAME
706
points at a new database name
707
@param[in] new_name not NULL if ALTER EVENT RENAME
708
points at a new event name
710
@pre All semantic checks are performed outside this function,
711
it only updates the event definition on disk.
712
@pre We don't have any tables open in the given thread.
714
@retval FALSE success
715
@retval TRUE error (reported)
719
Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
720
LEX_STRING *new_dbname,
721
LEX_STRING *new_name)
723
CHARSET_INFO *scs= system_charset_info;
725
sp_head *sp= thd->lex->sphead;
726
ulong saved_mode= thd->variables.sql_mode;
729
DBUG_ENTER("Event_db_repository::update_event");
731
/* None or both must be set */
732
DBUG_ASSERT((new_dbname && new_name) || new_dbname == new_name);
734
/* Reset sql_mode during data dictionary operations. */
735
thd->variables.sql_mode= 0;
737
if (open_event_table(thd, TL_WRITE, &table))
740
DBUG_PRINT("info", ("dbname: %s", parse_data->dbname.str));
741
DBUG_PRINT("info", ("name: %s", parse_data->name.str));
742
DBUG_PRINT("info", ("user: %s", parse_data->definer.str));
744
/* first look whether we overwrite */
747
DBUG_PRINT("info", ("rename to: %s@%s", new_dbname->str, new_name->str));
748
if (!find_named_event(*new_dbname, *new_name, table))
750
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->str);
755
...and then if there is such an event. Don't exchange the blocks
756
because you will get error 120 from table handler because new_name will
757
overwrite the key and SE will tell us that it cannot find the already found
758
row (copied into record[1] later
760
if (find_named_event(parse_data->dbname, parse_data->name, table))
762
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), parse_data->name.str);
766
store_record(table,record[1]);
769
We check whether ALTER EVENT was given dates that are in the past.
770
However to know how to react, we need the ON COMPLETION type. The
771
check is deferred to this point because by now we have the previous
772
setting (from the event-table) to fall back on if nothing was specified
773
in the ALTER EVENT-statement.
776
if (parse_data->check_dates(thd,
777
(int) table->field[ET_FIELD_ON_COMPLETION]->val_int()))
780
/* Don't update create on row update. */
781
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
784
mysql_event_fill_row() calls my_error() in case of error so no need to
787
if (mysql_event_fill_row(thd, table, parse_data, sp, saved_mode, TRUE))
792
table->field[ET_FIELD_DB]->store(new_dbname->str, new_dbname->length, scs);
793
table->field[ET_FIELD_NAME]->store(new_name->str, new_name->length, scs);
796
if ((ret= table->file->ha_update_row(table->record[1], table->record[0])))
798
table->file->print_error(ret, MYF(0));
805
close_thread_tables(thd);
806
thd->variables.sql_mode= saved_mode;
807
DBUG_RETURN(test(ret));
812
Delete event record from mysql.event table.
814
@param[in,out] thd thread handle
815
@param[in] db Database name
816
@param[in] name Event name
817
@param[in] drop_if_exists DROP IF EXISTS clause was specified.
818
If set, and the event does not exist,
819
the error is downgraded to a warning.
821
@retval FALSE success
822
@retval TRUE error (reported)
826
Event_db_repository::drop_event(THD *thd, LEX_STRING db, LEX_STRING name,
832
DBUG_ENTER("Event_db_repository::drop_event");
833
DBUG_PRINT("enter", ("%s@%s", db.str, name.str));
835
if (open_event_table(thd, TL_WRITE, &table))
838
if (!find_named_event(db, name, table))
840
if ((ret= table->file->ha_delete_row(table->record[0])))
841
table->file->print_error(ret, MYF(0));
845
/* Event not found */
848
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
852
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
853
ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
859
close_thread_tables(thd);
861
DBUG_RETURN(test(ret));
866
Positions the internal pointer of `table` to the place where (db, name)
869
In case search succeeded, the table cursor points at the found row.
871
@param[in] db database name
872
@param[in] name event name
873
@param[in,out] table mysql.event table
876
@retval FALSE an event with such db/name key exists
877
@retval TRUE no record found or an error occured.
881
Event_db_repository::find_named_event(LEX_STRING db, LEX_STRING name,
884
uchar key[MAX_KEY_LENGTH];
885
DBUG_ENTER("Event_db_repository::find_named_event");
886
DBUG_PRINT("enter", ("name: %.*s", (int) name.length, name.str));
889
Create key to find row. We have to use field->store() to be able to
890
handle VARCHAR and CHAR fields.
891
Assumption here is that the two first fields in the table are
892
'db' and 'name' and the first key is the primary key over the
895
if (db.length > table->field[ET_FIELD_DB]->field_length ||
896
name.length > table->field[ET_FIELD_NAME]->field_length)
899
table->field[ET_FIELD_DB]->store(db.str, db.length, &my_charset_bin);
900
table->field[ET_FIELD_NAME]->store(name.str, name.length, &my_charset_bin);
902
key_copy(key, table->record[0], table->key_info, table->key_info->key_length);
904
if (table->file->index_read_idx_map(table->record[0], 0, key, HA_WHOLE_KEY,
907
DBUG_PRINT("info", ("Row not found"));
911
DBUG_PRINT("info", ("Row found!"));
917
Drops all events in the selected database, from mysql.event.
920
Event_db_repository::drop_schema_events()
922
schema The database to clean from events
926
Event_db_repository::drop_schema_events(THD *thd, LEX_STRING schema)
928
DBUG_ENTER("Event_db_repository::drop_schema_events");
929
drop_events_by_field(thd, ET_FIELD_DB, schema);
935
Drops all events which have a specific value of a field.
937
@pre The thread handle has no open tables.
939
@param[in,out] thd Thread
940
@param[in,out] table mysql.event TABLE
941
@param[in] field Which field of the row to use for matching
942
@param[in] field_value The value that should match
946
Event_db_repository::drop_events_by_field(THD *thd,
947
enum enum_events_table_field field,
948
LEX_STRING field_value)
952
READ_RECORD read_record_info;
953
DBUG_ENTER("Event_db_repository::drop_events_by_field");
954
DBUG_PRINT("enter", ("field=%d field_value=%s", field, field_value.str));
956
if (open_event_table(thd, TL_WRITE, &table))
959
/* only enabled events are in memory, so we go now and delete the rest */
960
init_read_record(&read_record_info, thd, table, NULL, 1, 0, FALSE);
961
while (!ret && !(read_record_info.read_record(&read_record_info)) )
963
char *et_field= get_field(thd->mem_root, table->field[field]);
965
/* et_field may be NULL if the table is corrupted or out of memory */
968
LEX_STRING et_field_lex= { et_field, strlen(et_field) };
969
DBUG_PRINT("info", ("Current event %s name=%s", et_field,
970
get_field(thd->mem_root,
971
table->field[ET_FIELD_NAME])));
973
if (!sortcmp_lex_string(et_field_lex, field_value, system_charset_info))
975
DBUG_PRINT("info", ("Dropping"));
976
if ((ret= table->file->ha_delete_row(table->record[0])))
977
table->file->print_error(ret, MYF(0));
981
end_read_record(&read_record_info);
982
close_thread_tables(thd);
989
Looks for a named event in mysql.event and then loads it from
992
@pre The given thread does not have open tables.
994
@retval FALSE success
999
Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname,
1000
LEX_STRING name, Event_basic *etn)
1004
ulong saved_mode= thd->variables.sql_mode;
1006
DBUG_ENTER("Event_db_repository::load_named_event");
1007
DBUG_PRINT("enter",("thd: 0x%lx name: %*s", (long) thd,
1008
(int) name.length, name.str));
1010
/* Reset sql_mode during data dictionary operations. */
1011
thd->variables.sql_mode= 0;
1013
if (!(ret= open_event_table(thd, TL_READ, &table)))
1015
if ((ret= find_named_event(dbname, name, table)))
1016
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
1017
else if ((ret= etn->load_from_row(thd, table)))
1018
my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
1020
close_thread_tables(thd);
1023
thd->variables.sql_mode= saved_mode;
1029
Update the event record in mysql.event table with a changed status
1030
and/or last execution time.
1032
@pre The thread handle does not have open tables.
1036
Event_db_repository::
1037
update_timing_fields_for_event(THD *thd,
1038
LEX_STRING event_db_name,
1039
LEX_STRING event_name,
1040
bool update_last_executed,
1041
my_time_t last_executed,
1048
bool save_binlog_row_based;
1050
DBUG_ENTER("Event_db_repository::update_timing_fields_for_event");
1053
Turn off row binlogging of event timing updates. These are not used
1054
for RBR of events replicated to the slave.
1056
save_binlog_row_based= thd->current_stmt_binlog_row_based;
1057
thd->clear_current_stmt_binlog_row_based();
1059
DBUG_ASSERT(thd->security_ctx->master_access & SUPER_ACL);
1061
if (open_event_table(thd, TL_WRITE, &table))
1064
fields= table->field;
1066
if (find_named_event(event_db_name, event_name, table))
1069
store_record(table, record[1]);
1070
/* Don't update create on row update. */
1071
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
1073
if (update_last_executed)
1076
my_tz_OFFSET0->gmt_sec_to_TIME(&time, last_executed);
1078
fields[ET_FIELD_LAST_EXECUTED]->set_notnull();
1079
fields[ET_FIELD_LAST_EXECUTED]->store_time(&time,
1080
MYSQL_TIMESTAMP_DATETIME);
1084
fields[ET_FIELD_STATUS]->set_notnull();
1085
fields[ET_FIELD_STATUS]->store(status, TRUE);
1088
if ((ret= table->file->ha_update_row(table->record[1], table->record[0])))
1090
table->file->print_error(ret, MYF(0));
1098
close_thread_tables(thd);
1099
/* Restore the state of binlog format */
1100
thd->current_stmt_binlog_row_based= save_binlog_row_based;
1102
DBUG_RETURN(test(ret));
1107
Open mysql.db, mysql.user and mysql.event and check whether:
1108
- mysql.db exists and is up to date (or from a newer version of MySQL),
1109
- mysql.user has column Event_priv at an expected position,
1110
- mysql.event exists and is up to date (or from a newer version of
1113
This function is called only when the server is started.
1114
@pre The passed in thread handle has no open tables.
1117
@retval TRUE Error, an error message is output to the error log.
1121
Event_db_repository::check_system_tables(THD *thd)
1125
const unsigned int event_priv_column_position= 29;
1127
DBUG_ENTER("Event_db_repository::check_system_tables");
1128
DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
1131
/* Check mysql.db */
1132
tables.init_one_table("mysql", "db", TL_READ);
1134
if (simple_open_n_lock_tables(thd, &tables))
1137
sql_print_error("Cannot open mysql.db");
1141
if (table_intact.check(tables.table, &mysql_db_table_def))
1144
close_thread_tables(thd);
1146
/* Check mysql.user */
1147
tables.init_one_table("mysql", "user", TL_READ);
1149
if (simple_open_n_lock_tables(thd, &tables))
1152
sql_print_error("Cannot open mysql.user");
1156
if (tables.table->s->fields < event_priv_column_position ||
1157
strncmp(tables.table->field[event_priv_column_position]->field_name,
1158
STRING_WITH_LEN("Event_priv")))
1160
sql_print_error("mysql.user has no `Event_priv` column at position %d",
1161
event_priv_column_position);
1164
close_thread_tables(thd);
1166
/* Check mysql.event */
1167
tables.init_one_table("mysql", "event", TL_READ);
1169
if (simple_open_n_lock_tables(thd, &tables))
1172
sql_print_error("Cannot open mysql.event");
1176
if (table_intact.check(tables.table, &event_table_def))
1178
close_thread_tables(thd);
1181
DBUG_RETURN(test(ret));
1185
@} (End of group Event_Scheduler)