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