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