1 /*
2    Copyright (c) 2006, 2017, Oracle and/or its affiliates. All rights reserved.
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   DBUG_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     DBUG_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     DBUG_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   DBUG_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   DBUG_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   DBUG_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   DBUG_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   DBUG_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