1 /*
2 Copyright (c) 2006, 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
22 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
23
24 #include "event_db_repository.h"
25
26 #include "sql_base.h" // close_thread_tables
27 #include "key.h" // key_copy
28 #include "sql_db.h" // get_default_db_collation
29 #include "sql_time.h" // interval_type_to_name
30 #include "tztime.h" // struct Time_zone
31 #include "auth_common.h" // SUPER_ACL, MYSQL_DB_FIELD_COUNT, mysql_db_table_fields
32 #include "records.h" // init_read_record, end_read_record
33 #include "sp_head.h"
34 #include "event_data_objects.h"
35 #include "event_parse_data.h"
36 #include "events.h"
37 #include "sql_show.h"
38 #include "lock.h" // MYSQL_LOCK_IGNORE_TIMEOUT
39 #include "log.h"
40 #include "item_timefunc.h" // Item_func_now_local
41
42 /**
43 @addtogroup Event_Scheduler
44 @{
45 */
46
47 static
48 const TABLE_FIELD_TYPE event_table_fields[ET_FIELD_COUNT] =
49 {
50 {
51 { C_STRING_WITH_LEN("db") },
52 { C_STRING_WITH_LEN("char(64)") },
53 { C_STRING_WITH_LEN("utf8") }
54 },
55 {
56 { C_STRING_WITH_LEN("name") },
57 { C_STRING_WITH_LEN("char(64)") },
58 { C_STRING_WITH_LEN("utf8") }
59 },
60 {
61 { C_STRING_WITH_LEN("body") },
62 { C_STRING_WITH_LEN("longblob") },
63 {NULL, 0}
64 },
65 {
66 { C_STRING_WITH_LEN("definer") },
67 { C_STRING_WITH_LEN("char(93)") },
68 { C_STRING_WITH_LEN("utf8") }
69 },
70 {
71 { C_STRING_WITH_LEN("execute_at") },
72 { C_STRING_WITH_LEN("datetime") },
73 {NULL, 0}
74 },
75 {
76 { C_STRING_WITH_LEN("interval_value") },
77 { C_STRING_WITH_LEN("int(11)") },
78 {NULL, 0}
79 },
80 {
81 { C_STRING_WITH_LEN("interval_field") },
82 { C_STRING_WITH_LEN("enum('YEAR','QUARTER','MONTH','DAY',"
83 "'HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR',"
84 "'DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND',"
85 "'DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND',"
86 "'SECOND_MICROSECOND')") },
87 {NULL, 0}
88 },
89 {
90 { C_STRING_WITH_LEN("created") },
91 { C_STRING_WITH_LEN("timestamp") },
92 {NULL, 0}
93 },
94 {
95 { C_STRING_WITH_LEN("modified") },
96 { C_STRING_WITH_LEN("timestamp") },
97 {NULL, 0}
98 },
99 {
100 { C_STRING_WITH_LEN("last_executed") },
101 { C_STRING_WITH_LEN("datetime") },
102 {NULL, 0}
103 },
104 {
105 { C_STRING_WITH_LEN("starts") },
106 { C_STRING_WITH_LEN("datetime") },
107 {NULL, 0}
108 },
109 {
110 { C_STRING_WITH_LEN("ends") },
111 { C_STRING_WITH_LEN("datetime") },
112 {NULL, 0}
113 },
114 {
115 { C_STRING_WITH_LEN("status") },
116 { C_STRING_WITH_LEN("enum('ENABLED','DISABLED','SLAVESIDE_DISABLED')") },
117 {NULL, 0}
118 },
119 {
120 { C_STRING_WITH_LEN("on_completion") },
121 { C_STRING_WITH_LEN("enum('DROP','PRESERVE')") },
122 {NULL, 0}
123 },
124 {
125 { C_STRING_WITH_LEN("sql_mode") },
126 { C_STRING_WITH_LEN("set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES',"
127 "'IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION',"
128 "'NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB',"
129 "'NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40',"
130 "'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES',"
131 "'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES',"
132 "'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER',"
133 "'HIGH_NOT_PRECEDENCE','NO_ENGINE_SUBSTITUTION','PAD_CHAR_TO_FULL_LENGTH')") },
134 {NULL, 0}
135 },
136 {
137 { C_STRING_WITH_LEN("comment") },
138 { C_STRING_WITH_LEN("char(64)") },
139 { C_STRING_WITH_LEN("utf8") }
140 },
141 {
142 { C_STRING_WITH_LEN("originator") },
143 { C_STRING_WITH_LEN("int(10)") },
144 {NULL, 0}
145 },
146 {
147 { C_STRING_WITH_LEN("time_zone") },
148 { C_STRING_WITH_LEN("char(64)") },
149 { C_STRING_WITH_LEN("latin1") }
150 },
151 {
152 { C_STRING_WITH_LEN("character_set_client") },
153 { C_STRING_WITH_LEN("char(32)") },
154 { C_STRING_WITH_LEN("utf8") }
155 },
156 {
157 { C_STRING_WITH_LEN("collation_connection") },
158 { C_STRING_WITH_LEN("char(32)") },
159 { C_STRING_WITH_LEN("utf8") }
160 },
161 {
162 { C_STRING_WITH_LEN("db_collation") },
163 { C_STRING_WITH_LEN("char(32)") },
164 { C_STRING_WITH_LEN("utf8") }
165 },
166 {
167 { C_STRING_WITH_LEN("body_utf8") },
168 { C_STRING_WITH_LEN("longblob") },
169 { NULL, 0 }
170 }
171 };
172
173 static const TABLE_FIELD_DEF
174 event_table_def= {ET_FIELD_COUNT, event_table_fields};
175
176 class Event_db_intact : public Table_check_intact
177 {
178 private:
179 bool silence_error;
180 public:
Event_db_intact()181 Event_db_intact() : silence_error(FALSE) { has_keys= TRUE; }
182 my_bool check_event_table(TABLE *table);
183
184 protected:
report_error(uint,const char * fmt,...)185 void report_error(uint, const char *fmt, ...)
186 {
187 if(silence_error == TRUE)
188 return;
189
190 va_list args;
191 va_start(args, fmt);
192 error_log_print(ERROR_LEVEL, fmt, args);
193 va_end(args);
194 }
195 };
196
check_event_table(TABLE * table)197 my_bool Event_db_intact::check_event_table(TABLE *table)
198 {
199 silence_error= TRUE;
200 my_bool error= check(table, &event_table_def);
201 silence_error= FALSE;
202 if (!error)
203 return FALSE;
204
205 //This could have failed because of definer column being 77 characters long
206 uint32 original_definer_length= table->field[3]->field_length;
207 table->field[3]->field_length= (USERNAME_CHAR_LENGTH + HOSTNAME_LENGTH + 1) *
208 table->field[3]->charset()->mbmaxlen;
209
210 error= check(table, &event_table_def);
211
212 table->field[3]->field_length= original_definer_length;
213
214 return error;
215 }
216
217 /** In case of an error, a message is printed to the error log. */
218 static Event_db_intact table_intact;
219
220
221 /**
222 Puts some data common to CREATE and ALTER EVENT into a row.
223
224 Used both when an event is created and when it is altered.
225
226 @param thd THD
227 @param table The row to fill out
228 @param et Event's data
229 @param sp Event stored routine
230 @param is_update CREATE EVENT or ALTER EVENT
231
232 @retval FALSE success
233 @retval TRUE error
234 */
235
236 static bool
mysql_event_fill_row(THD * thd,TABLE * table,Event_parse_data * et,sp_head * sp,sql_mode_t sql_mode,my_bool is_update)237 mysql_event_fill_row(THD *thd,
238 TABLE *table,
239 Event_parse_data *et,
240 sp_head *sp,
241 sql_mode_t sql_mode,
242 my_bool is_update)
243 {
244 CHARSET_INFO *scs= system_charset_info;
245 enum enum_events_table_field f_num;
246 Field **fields= table->field;
247 int rs= FALSE;
248
249 DBUG_ENTER("mysql_event_fill_row");
250
251 DBUG_PRINT("info", ("dbname=[%s]", et->dbname.str));
252 DBUG_PRINT("info", ("name =[%s]", et->name.str));
253
254 assert(et->on_completion != Event_parse_data::ON_COMPLETION_DEFAULT);
255
256 if (table->s->fields < ET_FIELD_COUNT)
257 {
258 /*
259 Safety: this can only happen if someone started the server
260 and then altered mysql.event.
261 */
262 my_error(ER_COL_COUNT_DOESNT_MATCH_CORRUPTED_V2, MYF(0),
263 table->s->db.str, table->s->table_name.str,
264 (int) ET_FIELD_COUNT, table->s->fields);
265 DBUG_RETURN(TRUE);
266 }
267
268 if (fields[f_num= ET_FIELD_DEFINER]->
269 store(et->definer.str, et->definer.length, scs))
270 {
271 if(fields[ET_FIELD_DEFINER]->field_length <
272 (USERNAME_CHAR_LENGTH + HOSTNAME_LENGTH + 1) *
273 table->field[3]->charset()->mbmaxlen)
274 {
275 my_error(ER_USER_COLUMN_OLD_LENGTH, MYF(0),
276 fields[ET_FIELD_DEFINER]->field_name);
277 DBUG_RETURN(TRUE);
278 }
279 goto err_truncate;
280 }
281
282 if (fields[f_num= ET_FIELD_DB]->store(et->dbname.str, et->dbname.length, scs))
283 goto err_truncate;
284
285 if (fields[f_num= ET_FIELD_NAME]->store(et->name.str, et->name.length, scs))
286 goto err_truncate;
287
288 /* ON_COMPLETION field is NOT NULL thus not calling set_notnull()*/
289 rs|= fields[ET_FIELD_ON_COMPLETION]->store((longlong)et->on_completion, TRUE);
290
291 /*
292 Set STATUS value unconditionally in case of CREATE EVENT.
293 For ALTER EVENT set it only if value of this field was changed.
294 Since STATUS field is NOT NULL call to set_notnull() is not needed.
295 */
296 if (!is_update || et->status_changed)
297 rs|= fields[ET_FIELD_STATUS]->store((longlong)et->status, TRUE);
298 rs|= fields[ET_FIELD_ORIGINATOR]->store(et->originator, TRUE);
299
300 /*
301 Change the SQL_MODE only if body was present in an ALTER EVENT and of course
302 always during CREATE EVENT.
303 */
304 if (et->body_changed)
305 {
306 assert(sp->m_body.str);
307
308 rs|= fields[ET_FIELD_SQL_MODE]->store((longlong)sql_mode, TRUE);
309
310 if (fields[f_num= ET_FIELD_BODY]->store(sp->m_body.str,
311 sp->m_body.length,
312 scs))
313 {
314 goto err_truncate;
315 }
316 }
317
318 if (et->expression)
319 {
320 const String *tz_name= thd->variables.time_zone->get_name();
321 if (!is_update || !et->starts_null)
322 {
323 fields[ET_FIELD_TIME_ZONE]->set_notnull();
324 rs|= fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(),
325 tz_name->charset());
326 }
327
328 fields[ET_FIELD_INTERVAL_EXPR]->set_notnull();
329 rs|= fields[ET_FIELD_INTERVAL_EXPR]->store(et->expression, TRUE);
330
331 fields[ET_FIELD_TRANSIENT_INTERVAL]->set_notnull();
332
333 rs|= fields[ET_FIELD_TRANSIENT_INTERVAL]->
334 store(interval_type_to_name[et->interval].str,
335 interval_type_to_name[et->interval].length,
336 scs);
337
338 fields[ET_FIELD_EXECUTE_AT]->set_null();
339
340 if (!et->starts_null)
341 {
342 MYSQL_TIME time;
343 my_tz_OFFSET0->gmt_sec_to_TIME(&time, et->starts);
344
345 fields[ET_FIELD_STARTS]->set_notnull();
346 fields[ET_FIELD_STARTS]->store_time(&time);
347 }
348
349 if (!et->ends_null)
350 {
351 MYSQL_TIME time;
352 my_tz_OFFSET0->gmt_sec_to_TIME(&time, et->ends);
353
354 fields[ET_FIELD_ENDS]->set_notnull();
355 fields[ET_FIELD_ENDS]->store_time(&time);
356 }
357 }
358 else if (et->execute_at)
359 {
360 const String *tz_name= thd->variables.time_zone->get_name();
361 fields[ET_FIELD_TIME_ZONE]->set_notnull();
362 rs|= fields[ET_FIELD_TIME_ZONE]->store(tz_name->ptr(), tz_name->length(),
363 tz_name->charset());
364
365 fields[ET_FIELD_INTERVAL_EXPR]->set_null();
366 fields[ET_FIELD_TRANSIENT_INTERVAL]->set_null();
367 fields[ET_FIELD_STARTS]->set_null();
368 fields[ET_FIELD_ENDS]->set_null();
369
370 MYSQL_TIME time;
371 my_tz_OFFSET0->gmt_sec_to_TIME(&time, et->execute_at);
372
373 fields[ET_FIELD_EXECUTE_AT]->set_notnull();
374 fields[ET_FIELD_EXECUTE_AT]->store_time(&time);
375 }
376 else
377 {
378 assert(is_update);
379 /*
380 it is normal to be here when the action is update
381 this is an error if the action is create. something is borked
382 */
383 }
384
385 Item_func_now_local::store_in(fields[ET_FIELD_MODIFIED]);
386
387 if (et->comment.str)
388 {
389 if (fields[f_num= ET_FIELD_COMMENT]->
390 store(et->comment.str, et->comment.length, scs))
391 goto err_truncate;
392 }
393
394 fields[ET_FIELD_CHARACTER_SET_CLIENT]->set_notnull();
395 rs|= fields[ET_FIELD_CHARACTER_SET_CLIENT]->store(
396 thd->variables.character_set_client->csname,
397 strlen(thd->variables.character_set_client->csname),
398 system_charset_info);
399
400 fields[ET_FIELD_COLLATION_CONNECTION]->set_notnull();
401 rs|= fields[ET_FIELD_COLLATION_CONNECTION]->store(
402 thd->variables.collation_connection->name,
403 strlen(thd->variables.collation_connection->name),
404 system_charset_info);
405
406 {
407 const CHARSET_INFO *db_cl= get_default_db_collation(thd, et->dbname.str);
408
409 fields[ET_FIELD_DB_COLLATION]->set_notnull();
410 rs|= fields[ET_FIELD_DB_COLLATION]->store(db_cl->name,
411 strlen(db_cl->name),
412 system_charset_info);
413 }
414
415 if (et->body_changed)
416 {
417 fields[ET_FIELD_BODY_UTF8]->set_notnull();
418 rs|= fields[ET_FIELD_BODY_UTF8]->store(sp->m_body_utf8.str,
419 sp->m_body_utf8.length,
420 system_charset_info);
421 }
422
423 if (rs)
424 {
425 my_error(ER_EVENT_STORE_FAILED, MYF(0), fields[f_num]->field_name, rs);
426 DBUG_RETURN(TRUE);
427 }
428
429 DBUG_RETURN(FALSE);
430
431 err_truncate:
432 my_error(ER_EVENT_DATA_TOO_LONG, MYF(0), fields[f_num]->field_name);
433 DBUG_RETURN(TRUE);
434 }
435
436
437 /*
438 Performs an index scan of event_table (mysql.event) and fills schema_table.
439
440 SYNOPSIS
441 Event_db_repository::index_read_for_db_for_i_s()
442 thd Thread
443 schema_table The I_S.EVENTS table
444 event_table The event table to use for loading (mysql.event)
445 db For which schema to do an index scan.
446
447 RETURN VALUE
448 0 OK
449 1 Error
450 */
451
452 bool
index_read_for_db_for_i_s(THD * thd,TABLE * schema_table,TABLE * event_table,const char * db)453 Event_db_repository::index_read_for_db_for_i_s(THD *thd, TABLE *schema_table,
454 TABLE *event_table,
455 const char *db)
456 {
457 CHARSET_INFO *scs= system_charset_info;
458 KEY *key_info;
459 uint key_len;
460 uchar *key_buf= NULL;
461
462 DBUG_ENTER("Event_db_repository::index_read_for_db_for_i_s");
463
464 DBUG_PRINT("info", ("Using prefix scanning on PK"));
465
466 int ret= event_table->file->ha_index_init(0, 1);
467 if (ret)
468 {
469 event_table->file->print_error(ret, MYF(0));
470 DBUG_RETURN(true);
471 }
472
473 key_info= event_table->key_info;
474
475 if (key_info->user_defined_key_parts == 0 ||
476 key_info->key_part[0].field != event_table->field[ET_FIELD_DB])
477 {
478 /* Corrupted table: no index or index on a wrong column */
479 my_error(ER_CANNOT_LOAD_FROM_TABLE_V2, MYF(0), "mysql", "event");
480 ret= 1;
481 goto end;
482 }
483
484 event_table->field[ET_FIELD_DB]->store(db, strlen(db), scs);
485 key_len= key_info->key_part[0].store_length;
486
487 if (!(key_buf= (uchar *)alloc_root(thd->mem_root, key_len)))
488 {
489 /* Don't send error, it would be done by sql_alloc_error_handler() */
490 ret= 1;
491 goto end;
492 }
493
494 key_copy(key_buf, event_table->record[0], key_info, key_len);
495 if (!(ret= event_table->file->ha_index_read_map(event_table->record[0], key_buf,
496 (key_part_map)1,
497 HA_READ_KEY_EXACT)))
498 {
499 DBUG_PRINT("info",("Found rows. Let's retrieve them. ret=%d", ret));
500 do
501 {
502 ret= copy_event_to_schema_table(thd, schema_table, event_table);
503 if (ret == 0)
504 ret= event_table->file->ha_index_next_same(event_table->record[0],
505 key_buf, key_len);
506 } while (ret == 0);
507 }
508 DBUG_PRINT("info", ("Scan finished. ret=%d", ret));
509
510 /* ret is guaranteed to be != 0 */
511 if (ret == HA_ERR_END_OF_FILE || ret == HA_ERR_KEY_NOT_FOUND)
512 ret= 0;
513 else
514 event_table->file->print_error(ret, MYF(0));
515
516 end:
517 event_table->file->ha_index_end();
518
519 DBUG_RETURN(MY_TEST(ret));
520 }
521
522
523 /*
524 Performs a table scan of event_table (mysql.event) and fills schema_table.
525
526 SYNOPSIS
527 Events_db_repository::table_scan_all_for_i_s()
528 thd Thread
529 schema_table The I_S.EVENTS in memory table
530 event_table The event table to use for loading.
531
532 RETURN VALUE
533 FALSE OK
534 TRUE Error
535 */
536
537 bool
table_scan_all_for_i_s(THD * thd,TABLE * schema_table,TABLE * event_table)538 Event_db_repository::table_scan_all_for_i_s(THD *thd, TABLE *schema_table,
539 TABLE *event_table)
540 {
541 int ret;
542 READ_RECORD read_record_info;
543 DBUG_ENTER("Event_db_repository::table_scan_all_for_i_s");
544
545 if (init_read_record(&read_record_info, thd, event_table, NULL, 1, 1, FALSE))
546 DBUG_RETURN(TRUE);
547
548 /*
549 rr_sequential, in read_record(), returns 137==HA_ERR_END_OF_FILE,
550 but rr_handle_error returns -1 for that reason. Thus, read_record()
551 returns -1 eventually.
552 */
553 do
554 {
555 ret= read_record_info.read_record(&read_record_info);
556 if (ret == 0)
557 ret= copy_event_to_schema_table(thd, schema_table, event_table);
558 } while (ret == 0);
559
560 DBUG_PRINT("info", ("Scan finished. ret=%d", ret));
561 end_read_record(&read_record_info);
562
563 /* ret is guaranteed to be != 0 */
564 DBUG_RETURN(ret == -1 ? FALSE : TRUE);
565 }
566
567
568 /**
569 Fills I_S.EVENTS with data loaded from mysql.event. Also used by
570 SHOW EVENTS
571
572 The reason we reset and backup open tables here is that this
573 function may be called from any query that accesses
574 INFORMATION_SCHEMA - including a query that is issued from
575 a pre-locked statement, one that already has open and locked
576 tables.
577
578 @retval FALSE success
579 @retval TRUE error
580 */
581
582 bool
fill_schema_events(THD * thd,TABLE_LIST * i_s_table,const char * db)583 Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *i_s_table,
584 const char *db)
585 {
586 TABLE *schema_table= i_s_table->table;
587 Open_tables_backup open_tables_backup;
588 TABLE_LIST event_table;
589 int ret= 0;
590
591 DBUG_ENTER("Event_db_repository::fill_schema_events");
592 DBUG_PRINT("info",("db=%s", db? db:"(null)"));
593
594 event_table.init_one_table("mysql", 5, "event", 5, "event", TL_READ);
595
596 if (open_nontrans_system_tables_for_read(thd, &event_table,
597 &open_tables_backup))
598 {
599 DBUG_RETURN(TRUE);
600 }
601
602 if (table_intact.check_event_table(event_table.table))
603 {
604 close_nontrans_system_tables(thd, &open_tables_backup);
605 my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
606 DBUG_RETURN(TRUE);
607 }
608
609 /*
610 1. SELECT I_S => use table scan. I_S.EVENTS does not guarantee order
611 thus we won't order it. OTOH, SHOW EVENTS will be
612 ordered.
613 2. SHOW EVENTS => PRIMARY KEY with prefix scanning on (db)
614 Reasoning: Events are per schema, therefore a scan over an index
615 will save use from doing a table scan and comparing
616 every single row's `db` with the schema which we show.
617 */
618 if (db)
619 ret= index_read_for_db_for_i_s(thd, schema_table, event_table.table, db);
620 else
621 ret= table_scan_all_for_i_s(thd, schema_table, event_table.table);
622
623 close_nontrans_system_tables(thd, &open_tables_backup);
624
625 DBUG_PRINT("info", ("Return code=%d", ret));
626 DBUG_RETURN(ret);
627 }
628
629
630 /**
631 Open mysql.event table for read.
632
633 It's assumed that the caller knows what they are doing:
634 - whether it was necessary to reset-and-backup the open tables state
635 - whether the requested lock does not lead to a deadlock
636 - whether this open mode would work under LOCK TABLES, or inside a
637 stored function or trigger.
638
639 Note that if the table can't be locked successfully this operation will
640 close it. Therefore it provides guarantee that it either opens and locks
641 table or fails without leaving any tables open.
642
643 @param[in] thd Thread context
644 @param[in] lock_type How to lock the table
645 @param[out] table We will store the open table here
646
647 @retval TRUE open and lock failed - an error message is pushed into the
648 stack
649 @retval FALSE success
650 */
651
652 bool
open_event_table(THD * thd,enum thr_lock_type lock_type,TABLE ** table)653 Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type,
654 TABLE **table)
655 {
656 TABLE_LIST tables;
657 DBUG_ENTER("Event_db_repository::open_event_table");
658
659 tables.init_one_table("mysql", 5, "event", 5, "event", lock_type);
660
661 if (open_and_lock_tables(thd, &tables, MYSQL_LOCK_IGNORE_TIMEOUT))
662 DBUG_RETURN(TRUE);
663
664 *table= tables.table;
665 tables.table->use_all_columns();
666
667 if (table_intact.check_event_table(*table))
668 {
669 close_thread_tables(thd);
670 my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
671 DBUG_RETURN(TRUE);
672 }
673
674 DBUG_RETURN(FALSE);
675 }
676
677
678 /**
679 Creates an event record in mysql.event table.
680
681 Creates an event. Relies on mysql_event_fill_row which is shared with
682 ::update_event.
683
684 @pre All semantic checks must be performed outside. This function
685 only creates a record on disk.
686 @pre The thread handle has no open tables.
687
688 @param[in,out] thd THD
689 @param[in] parse_data Parsed event definition
690 @param[in] create_if_not TRUE if IF NOT EXISTS clause was provided
691 to CREATE EVENT statement
692 @param[out] event_already_exists When method is completed successfully
693 set to true if event already exists else
694 set to false
695 @retval FALSE success
696 @retval TRUE error
697 */
698
699 bool
create_event(THD * thd,Event_parse_data * parse_data,bool create_if_not,bool * event_already_exists)700 Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
701 bool create_if_not,
702 bool *event_already_exists)
703 {
704 int ret= 1;
705 TABLE *table= NULL;
706 sp_head *sp= thd->lex->sphead;
707 sql_mode_t saved_mode= thd->variables.sql_mode;
708 /*
709 Take a savepoint to release only the lock on mysql.event
710 table at the end but keep the global read lock and
711 possible other locks taken by the caller.
712 */
713 MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
714
715 DBUG_ENTER("Event_db_repository::create_event");
716
717 DBUG_PRINT("info", ("open mysql.event for update"));
718 assert(sp);
719
720 /* Reset sql_mode during data dictionary operations. */
721 thd->variables.sql_mode= 0;
722
723 if (open_event_table(thd, TL_WRITE, &table))
724 goto end;
725
726 DBUG_PRINT("info", ("name: %.*s", (int) parse_data->name.length,
727 parse_data->name.str));
728
729 DBUG_PRINT("info", ("check existance of an event with the same name"));
730 if (!find_named_event(parse_data->dbname, parse_data->name, table))
731 {
732 if (create_if_not)
733 {
734 *event_already_exists= true;
735 push_warning_printf(thd, Sql_condition::SL_NOTE,
736 ER_EVENT_ALREADY_EXISTS, ER(ER_EVENT_ALREADY_EXISTS),
737 parse_data->name.str);
738 ret= 0;
739 }
740 else
741 my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), parse_data->name.str);
742
743 goto end;
744 } else
745 *event_already_exists= false;
746
747 DBUG_PRINT("info", ("non-existent, go forward"));
748
749 restore_record(table, s->default_values); // Get default values for fields
750
751 if (system_charset_info->cset->
752 numchars(system_charset_info, parse_data->dbname.str,
753 parse_data->dbname.str + parse_data->dbname.length) >
754 table->field[ET_FIELD_DB]->char_length())
755 {
756 my_error(ER_TOO_LONG_IDENT, MYF(0), parse_data->dbname.str);
757 goto end;
758 }
759
760 if (system_charset_info->cset->
761 numchars(system_charset_info, parse_data->name.str,
762 parse_data->name.str + parse_data->name.length) >
763 table->field[ET_FIELD_NAME]->char_length())
764 {
765 my_error(ER_TOO_LONG_IDENT, MYF(0), parse_data->name.str);
766 goto end;
767 }
768
769 if (sp->m_body.length > table->field[ET_FIELD_BODY]->field_length)
770 {
771 my_error(ER_TOO_LONG_BODY, MYF(0), parse_data->name.str);
772 goto end;
773 }
774
775 Item_func_now_local::store_in(table->field[ET_FIELD_CREATED]);
776
777 /*
778 mysql_event_fill_row() calls my_error() in case of error so no need to
779 handle it here
780 */
781 if (mysql_event_fill_row(thd, table, parse_data, sp, saved_mode, FALSE))
782 goto end;
783
784 if ((ret= table->file->ha_write_row(table->record[0])))
785 {
786 table->file->print_error(ret, MYF(0));
787 goto end;
788 }
789 ret= 0;
790
791 end:
792 close_thread_tables(thd);
793 thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
794
795 thd->variables.sql_mode= saved_mode;
796 DBUG_RETURN(MY_TEST(ret));
797 }
798
799
800 /**
801 Used to execute ALTER EVENT. Pendant to Events::update_event().
802
803 @param[in,out] thd thread handle
804 @param[in] parse_data parsed event definition
805 @param[in] new_dbname not NULL if ALTER EVENT RENAME
806 points at a new database name
807 @param[in] new_name not NULL if ALTER EVENT RENAME
808 points at a new event name
809
810 @pre All semantic checks are performed outside this function,
811 it only updates the event definition on disk.
812 @pre We don't have any tables open in the given thread.
813
814 @retval FALSE success
815 @retval TRUE error (reported)
816 */
817
818 bool
update_event(THD * thd,Event_parse_data * parse_data,LEX_STRING * new_dbname,LEX_STRING * new_name)819 Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
820 LEX_STRING *new_dbname,
821 LEX_STRING *new_name)
822 {
823 CHARSET_INFO *scs= system_charset_info;
824 TABLE *table= NULL;
825 sp_head *sp= thd->lex->sphead;
826 sql_mode_t saved_mode= thd->variables.sql_mode;
827 /*
828 Take a savepoint to release only the lock on mysql.event
829 table at the end but keep the global read lock and
830 possible other locks taken by the caller.
831 */
832 MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
833 int ret= 1;
834
835 DBUG_ENTER("Event_db_repository::update_event");
836
837 /* None or both must be set */
838 assert((new_dbname && new_name) || new_dbname == new_name);
839
840 /* Reset sql_mode during data dictionary operations. */
841 thd->variables.sql_mode= 0;
842
843 if (open_event_table(thd, TL_WRITE, &table))
844 goto end;
845
846 DBUG_PRINT("info", ("dbname: %s", parse_data->dbname.str));
847 DBUG_PRINT("info", ("name: %s", parse_data->name.str));
848 DBUG_PRINT("info", ("user: %s", parse_data->definer.str));
849
850 /* first look whether we overwrite */
851 if (new_name)
852 {
853 DBUG_PRINT("info", ("rename to: %s@%s", new_dbname->str, new_name->str));
854 if (!find_named_event(*new_dbname, *new_name, table))
855 {
856 my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->str);
857 goto end;
858 }
859 }
860 /*
861 ...and then if there is such an event. Don't exchange the blocks
862 because you will get error 120 from table handler because new_name will
863 overwrite the key and SE will tell us that it cannot find the already found
864 row (copied into record[1] later
865 */
866 if (find_named_event(parse_data->dbname, parse_data->name, table))
867 {
868 my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), parse_data->name.str);
869 goto end;
870 }
871
872 store_record(table,record[1]);
873
874 /*
875 We check whether ALTER EVENT was given dates that are in the past.
876 However to know how to react, we need the ON COMPLETION type. The
877 check is deferred to this point because by now we have the previous
878 setting (from the event-table) to fall back on if nothing was specified
879 in the ALTER EVENT-statement.
880 */
881
882 if (parse_data->check_dates(thd,
883 (int) table->field[ET_FIELD_ON_COMPLETION]->val_int()))
884 goto end;
885
886 /*
887 mysql_event_fill_row() calls my_error() in case of error so no need to
888 handle it here
889 */
890 if (mysql_event_fill_row(thd, table, parse_data, sp, saved_mode, TRUE))
891 goto end;
892
893 if (new_dbname)
894 {
895 table->field[ET_FIELD_DB]->store(new_dbname->str, new_dbname->length, scs);
896 table->field[ET_FIELD_NAME]->store(new_name->str, new_name->length, scs);
897 }
898
899 if ((ret= table->file->ha_update_row(table->record[1], table->record[0])))
900 {
901 table->file->print_error(ret, MYF(0));
902 goto end;
903 }
904 ret= 0;
905
906 end:
907 close_thread_tables(thd);
908 thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
909
910 thd->variables.sql_mode= saved_mode;
911 DBUG_RETURN(MY_TEST(ret));
912 }
913
914
915 /**
916 Delete event record from mysql.event table.
917
918 @param[in,out] thd thread handle
919 @param[in] db Database name
920 @param[in] name Event name
921 @param[in] drop_if_exists DROP IF EXISTS clause was specified.
922 If set, and the event does not exist,
923 the error is downgraded to a warning.
924
925 @retval FALSE success
926 @retval TRUE error (reported)
927 */
928
929 bool
drop_event(THD * thd,LEX_STRING db,LEX_STRING name,bool drop_if_exists)930 Event_db_repository::drop_event(THD *thd, LEX_STRING db, LEX_STRING name,
931 bool drop_if_exists)
932 {
933 TABLE *table= NULL;
934 /*
935 Take a savepoint to release only the lock on mysql.event
936 table at the end but keep the global read lock and
937 possible other locks taken by the caller.
938 */
939 MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
940 int ret= 1;
941
942 /*
943 Turn off row binlogging of this statement and use statement-based so
944 that all supporting tables are updated for DROP EVENT command.
945 */
946 bool save_binlog_row_based;
947 if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
948 thd->clear_current_stmt_binlog_format_row();
949
950 DBUG_ENTER("Event_db_repository::drop_event");
951 DBUG_PRINT("enter", ("%s@%s", db.str, name.str));
952
953 if (open_event_table(thd, TL_WRITE, &table))
954 goto end;
955
956 if (!find_named_event(db, name, table))
957 {
958 if ((ret= table->file->ha_delete_row(table->record[0])))
959 table->file->print_error(ret, MYF(0));
960 goto end;
961 }
962
963 /* Event not found */
964 if (!drop_if_exists)
965 {
966 my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
967 goto end;
968 }
969
970 push_warning_printf(thd, Sql_condition::SL_NOTE,
971 ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
972 "Event", name.str);
973 ret= 0;
974
975 end:
976 close_thread_tables(thd);
977 thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
978
979 /* Restore the state of binlog format */
980 assert(!thd->is_current_stmt_binlog_format_row());
981 if (save_binlog_row_based)
982 thd->set_current_stmt_binlog_format_row();
983
984 DBUG_RETURN(MY_TEST(ret));
985 }
986
987
988 /**
989 Positions the internal pointer of `table` to the place where (db, name)
990 is stored.
991
992 In case search succeeded, the table cursor points at the found row.
993
994 @param[in] db database name
995 @param[in] name event name
996 @param[in,out] table mysql.event table
997
998
999 @retval FALSE an event with such db/name key exists
1000 @retval TRUE no record found or an error occured.
1001 */
1002
1003 bool
find_named_event(LEX_STRING db,LEX_STRING name,TABLE * table)1004 Event_db_repository::find_named_event(LEX_STRING db, LEX_STRING name,
1005 TABLE *table)
1006 {
1007 uchar key[MAX_KEY_LENGTH];
1008 DBUG_ENTER("Event_db_repository::find_named_event");
1009 DBUG_PRINT("enter", ("name: %.*s", (int) name.length, name.str));
1010
1011 /*
1012 Create key to find row. We have to use field->store() to be able to
1013 handle VARCHAR and CHAR fields.
1014 Assumption here is that the two first fields in the table are
1015 'db' and 'name' and the first key is the primary key over the
1016 same fields.
1017 */
1018 if (db.length > table->field[ET_FIELD_DB]->field_length ||
1019 name.length > table->field[ET_FIELD_NAME]->field_length)
1020 DBUG_RETURN(TRUE);
1021
1022 table->field[ET_FIELD_DB]->store(db.str, db.length, &my_charset_bin);
1023 table->field[ET_FIELD_NAME]->store(name.str, name.length, &my_charset_bin);
1024
1025 key_copy(key, table->record[0], table->key_info, table->key_info->key_length);
1026
1027 if (table->file->ha_index_read_idx_map(table->record[0], 0, key, HA_WHOLE_KEY,
1028 HA_READ_KEY_EXACT))
1029 {
1030 DBUG_PRINT("info", ("Row not found"));
1031 DBUG_RETURN(TRUE);
1032 }
1033
1034 DBUG_PRINT("info", ("Row found!"));
1035 DBUG_RETURN(FALSE);
1036 }
1037
1038
1039 /*
1040 Drops all events in the selected database, from mysql.event.
1041
1042 SYNOPSIS
1043 Event_db_repository::drop_schema_events()
1044 thd Thread
1045 schema The database to clean from events
1046 */
1047
1048 void
drop_schema_events(THD * thd,LEX_STRING schema)1049 Event_db_repository::drop_schema_events(THD *thd, LEX_STRING schema)
1050 {
1051 int ret= 0;
1052 TABLE *table= NULL;
1053 READ_RECORD read_record_info;
1054 enum enum_events_table_field field= ET_FIELD_DB;
1055 MDL_savepoint mdl_savepoint= thd->mdl_context.mdl_savepoint();
1056 DBUG_ENTER("Event_db_repository::drop_schema_events");
1057 DBUG_PRINT("enter", ("field=%d schema=%s", field, schema.str));
1058
1059 if (open_event_table(thd, TL_WRITE, &table))
1060 DBUG_VOID_RETURN;
1061
1062 /* only enabled events are in memory, so we go now and delete the rest */
1063 if (init_read_record(&read_record_info, thd, table, NULL, 1, 1, FALSE))
1064 DBUG_VOID_RETURN;
1065 while (!ret && !(read_record_info.read_record(&read_record_info)) )
1066 {
1067 char *et_field= get_field(thd->mem_root, table->field[field]);
1068
1069 /* et_field may be NULL if the table is corrupted or out of memory */
1070 if (et_field)
1071 {
1072 LEX_STRING et_field_lex= { et_field, strlen(et_field) };
1073 DBUG_PRINT("info", ("Current event %s name=%s", et_field,
1074 get_field(thd->mem_root,
1075 table->field[ET_FIELD_NAME])));
1076
1077 if (!sortcmp_lex_string(et_field_lex, schema, system_charset_info))
1078 {
1079 DBUG_PRINT("info", ("Dropping"));
1080 if ((ret= table->file->ha_delete_row(table->record[0])))
1081 table->file->print_error(ret, MYF(0));
1082 }
1083 }
1084 }
1085 end_read_record(&read_record_info);
1086 close_thread_tables(thd);
1087 /*
1088 Make sure to only release the MDL lock on mysql.event, not other
1089 metadata locks DROP DATABASE might have acquired.
1090 */
1091 thd->mdl_context.rollback_to_savepoint(mdl_savepoint);
1092
1093 DBUG_VOID_RETURN;
1094 }
1095
1096
1097 /**
1098 Looks for a named event in mysql.event and then loads it from
1099 the table.
1100
1101 @pre The given thread does not have open tables.
1102
1103 @retval FALSE success
1104 @retval TRUE error
1105 */
1106
1107 bool
load_named_event(THD * thd,LEX_STRING dbname,LEX_STRING name,Event_basic * etn)1108 Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname,
1109 LEX_STRING name, Event_basic *etn)
1110 {
1111 bool ret;
1112 sql_mode_t saved_mode= thd->variables.sql_mode;
1113 Open_tables_backup open_tables_backup;
1114 TABLE_LIST event_table;
1115
1116 DBUG_ENTER("Event_db_repository::load_named_event");
1117 DBUG_PRINT("enter",("thd: 0x%lx name: %*s", (long) thd,
1118 (int) name.length, name.str));
1119
1120 event_table.init_one_table("mysql", 5, "event", 5, "event", TL_READ);
1121
1122 /* Reset sql_mode during data dictionary operations. */
1123 thd->variables.sql_mode= 0;
1124
1125 /*
1126 We don't use open_event_table() here to make sure that SHOW
1127 CREATE EVENT works properly in transactional context, and
1128 does not release transactional metadata locks when the
1129 event table is closed.
1130 */
1131 if (!(ret= open_nontrans_system_tables_for_read(thd, &event_table,
1132 &open_tables_backup)))
1133 {
1134 if (table_intact.check_event_table(event_table.table))
1135 {
1136 close_nontrans_system_tables(thd, &open_tables_backup);
1137 my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
1138 DBUG_RETURN(TRUE);
1139 }
1140
1141 if ((ret= find_named_event(dbname, name, event_table.table)))
1142 my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
1143 else if ((ret= etn->load_from_row(thd, event_table.table)))
1144 my_error(ER_CANNOT_LOAD_FROM_TABLE_V2, MYF(0), "mysql", "event");
1145
1146 close_nontrans_system_tables(thd, &open_tables_backup);
1147 }
1148
1149 thd->variables.sql_mode= saved_mode;
1150 DBUG_RETURN(ret);
1151 }
1152
1153
1154 /**
1155 Update the event record in mysql.event table with a changed status
1156 and/or last execution time.
1157
1158 @pre The thread handle does not have open tables.
1159 */
1160
1161 bool
1162 Event_db_repository::
update_timing_fields_for_event(THD * thd,LEX_STRING event_db_name,LEX_STRING event_name,my_time_t last_executed,ulonglong status)1163 update_timing_fields_for_event(THD *thd,
1164 LEX_STRING event_db_name,
1165 LEX_STRING event_name,
1166 my_time_t last_executed,
1167 ulonglong status)
1168 {
1169 TABLE *table= NULL;
1170 Field **fields;
1171 int ret= 1;
1172 bool save_binlog_row_based;
1173 MYSQL_TIME time;
1174
1175 DBUG_ENTER("Event_db_repository::update_timing_fields_for_event");
1176
1177 /*
1178 Turn off row binlogging of event timing updates. These are not used
1179 for RBR of events replicated to the slave.
1180 */
1181 if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
1182 thd->clear_current_stmt_binlog_format_row();
1183
1184 assert(thd->security_context()->check_access(SUPER_ACL));
1185
1186 if (open_event_table(thd, TL_WRITE, &table))
1187 goto end;
1188
1189 fields= table->field;
1190
1191 if (find_named_event(event_db_name, event_name, table))
1192 goto end;
1193
1194 store_record(table, record[1]);
1195
1196 my_tz_OFFSET0->gmt_sec_to_TIME(&time, last_executed);
1197 fields[ET_FIELD_LAST_EXECUTED]->set_notnull();
1198 fields[ET_FIELD_LAST_EXECUTED]->store_time(&time);
1199
1200 fields[ET_FIELD_STATUS]->set_notnull();
1201 fields[ET_FIELD_STATUS]->store(status, TRUE);
1202
1203 if ((ret= table->file->ha_update_row(table->record[1], table->record[0])))
1204 {
1205 table->file->print_error(ret, MYF(0));
1206 goto end;
1207 }
1208
1209 ret= 0;
1210
1211 end:
1212 if (table)
1213 close_mysql_tables(thd);
1214
1215 /* Restore the state of binlog format */
1216 assert(!thd->is_current_stmt_binlog_format_row());
1217 if (save_binlog_row_based)
1218 thd->set_current_stmt_binlog_format_row();
1219
1220 DBUG_RETURN(MY_TEST(ret));
1221 }
1222
1223
1224 /**
1225 Open mysql.db, mysql.user and mysql.event and check whether:
1226 - mysql.db exists and is up to date (or from a newer version of MySQL),
1227 - mysql.user has column Event_priv at an expected position,
1228 - mysql.event exists and is up to date (or from a newer version of
1229 MySQL)
1230
1231 This function is called only when the server is started.
1232 @pre The passed in thread handle has no open tables.
1233
1234 @retval FALSE OK
1235 @retval TRUE Error, an error message is output to the error log.
1236 */
1237
1238 bool
check_system_tables(THD * thd)1239 Event_db_repository::check_system_tables(THD *thd)
1240 {
1241 TABLE_LIST tables;
1242 int ret= FALSE;
1243 const unsigned int event_priv_column_position= 28;
1244
1245 DBUG_ENTER("Event_db_repository::check_system_tables");
1246 DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
1247
1248 /* Check mysql.db */
1249 tables.init_one_table("mysql", 5, "db", 2, "db", TL_READ);
1250
1251 if (open_and_lock_tables(thd, &tables, MYSQL_LOCK_IGNORE_TIMEOUT))
1252 {
1253 ret= 1;
1254 sql_print_error("Cannot open mysql.db");
1255 }
1256 else
1257 {
1258 if (table_intact.check(tables.table, &mysql_db_table_def))
1259 ret= 1;
1260 close_acl_tables(thd);
1261 }
1262 /* Check mysql.user */
1263 tables.init_one_table("mysql", 5, "user", 4, "user", TL_READ);
1264
1265 if (open_and_lock_tables(thd, &tables, MYSQL_LOCK_IGNORE_TIMEOUT))
1266 {
1267 ret= 1;
1268 sql_print_error("Cannot open mysql.user");
1269 }
1270 else
1271 {
1272 if (tables.table->s->fields < event_priv_column_position ||
1273 strncmp(tables.table->field[event_priv_column_position]->field_name,
1274 STRING_WITH_LEN("Event_priv")))
1275 {
1276 sql_print_error("mysql.user has no `Event_priv` column at position %d",
1277 event_priv_column_position);
1278 ret= 1;
1279 }
1280 close_acl_tables(thd);
1281 }
1282 /* Check mysql.event */
1283 tables.init_one_table("mysql", 5, "event", 5, "event", TL_READ);
1284
1285 if (open_and_lock_tables(thd, &tables, MYSQL_LOCK_IGNORE_TIMEOUT))
1286 {
1287 ret= 1;
1288 sql_print_error("Cannot open mysql.event");
1289 }
1290 else
1291 {
1292 if(table_intact.check_event_table(tables.table))
1293 ret= 1;
1294 close_mysql_tables(thd);
1295 }
1296
1297 DBUG_RETURN(MY_TEST(ret));
1298 }
1299
1300 /**
1301 @} (End of group Event_Scheduler)
1302 */
1303