~ubuntu-branches/ubuntu/trusty/mariadb-5.5/trusty-proposed

« back to all changes in this revision

Viewing changes to sql/events.cc

  • Committer: Package Import Robot
  • Author(s): Otto Kekäläinen
  • Date: 2013-12-22 10:27:05 UTC
  • Revision ID: package-import@ubuntu.com-20131222102705-mndw7s12mz0szrcn
Tags: upstream-5.5.32
Import upstream version 5.5.32

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
   Copyright (c) 2005, 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-1301  USA */
 
16
 
 
17
#include "sql_priv.h"
 
18
#include "unireg.h"
 
19
#include "sql_parse.h"                          // check_access
 
20
#include "sql_base.h"                           // close_mysql_tables
 
21
#include "sql_show.h"                           // append_definer
 
22
#include "events.h"
 
23
#include "sql_db.h"                          // check_db_dir_existence
 
24
#include "sql_table.h"                       // write_bin_log
 
25
#include "tztime.h"                             // struct Time_zone
 
26
#include "sql_acl.h"                            // EVENT_ACL
 
27
#include "records.h"          // init_read_record, end_read_record
 
28
#include "event_data_objects.h"
 
29
#include "event_db_repository.h"
 
30
#include "event_queue.h"
 
31
#include "event_scheduler.h"
 
32
#include "sp_head.h" // for Stored_program_creation_ctx
 
33
#include "set_var.h"
 
34
#include "lock.h"   // lock_object_name
 
35
 
 
36
/**
 
37
  @addtogroup Event_Scheduler
 
38
  @{
 
39
*/
 
40
 
 
41
/*
 
42
 TODO list :
 
43
 - CREATE EVENT should not go into binary log! Does it now? The SQL statements
 
44
   issued by the EVENT are replicated.
 
45
   I have an idea how to solve the problem at failover. So the status field
 
46
   will be ENUM('DISABLED', 'ENABLED', 'SLAVESIDE_DISABLED').
 
47
   In this case when CREATE EVENT is replicated it should go into the binary
 
48
   as SLAVESIDE_DISABLED if it is ENABLED, when it's created as DISABLEd it
 
49
   should be replicated as disabled. If an event is ALTERed as DISABLED the
 
50
   query should go untouched into the binary log, when ALTERed as enable then
 
51
   it should go as SLAVESIDE_DISABLED. This is regarding the SQL interface.
 
52
   TT routines however modify mysql.event internally and this does not go the
 
53
   log so in this case queries has to be injected into the log...somehow... or
 
54
   maybe a solution is RBR for this case, because the event may go only from
 
55
   ENABLED to DISABLED status change and this is safe for replicating. As well
 
56
   an event may be deleted which is also safe for RBR.
 
57
 
 
58
 - Add logging to file
 
59
 
 
60
*/
 
61
 
 
62
 
 
63
/*
 
64
  If the user (un)intentionally removes an event directly from mysql.event
 
65
  the following sequence has to be used to be able to remove the in-memory
 
66
  counterpart.
 
67
  1. CREATE EVENT the_name ON SCHEDULE EVERY 1 SECOND DISABLE DO SELECT 1;
 
68
  2. DROP EVENT the_name
 
69
 
 
70
  In other words, the first one will create a row in mysql.event . In the
 
71
  second step because there will be a line, disk based drop will pass and
 
72
  the scheduler will remove the memory counterpart. The reason is that
 
73
  in-memory queue does not check whether the event we try to drop from memory
 
74
  is disabled. Disabled events are not kept in-memory because they are not
 
75
  eligible for execution.
 
76
*/
 
77
 
 
78
Event_queue *Events::event_queue;
 
79
Event_scheduler *Events::scheduler;
 
80
Event_db_repository *Events::db_repository;
 
81
ulong Events::opt_event_scheduler= Events::EVENTS_OFF;
 
82
bool Events::check_system_tables_error= FALSE;
 
83
 
 
84
 
 
85
/*
 
86
  Compares 2 LEX strings regarding case.
 
87
 
 
88
  SYNOPSIS
 
89
    sortcmp_lex_string()
 
90
      s   First LEX_STRING
 
91
      t   Second LEX_STRING
 
92
      cs  Charset
 
93
 
 
94
  RETURN VALUE
 
95
   -1   s < t
 
96
    0   s == t
 
97
    1   s > t
 
98
*/
 
99
 
 
100
int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
 
101
{
 
102
 return cs->coll->strnncollsp(cs, (uchar *) s.str,s.length,
 
103
                                  (uchar *) t.str,t.length, 0);
 
104
}
 
105
 
 
106
 
 
107
/**
 
108
  Push an error into the error stack if the system tables are
 
109
  not up to date.
 
110
*/
 
111
 
 
112
bool Events::check_if_system_tables_error()
 
113
{
 
114
  DBUG_ENTER("Events::check_if_system_tables_error");
 
115
 
 
116
  if (check_system_tables_error)
 
117
  {
 
118
    my_error(ER_EVENTS_DB_ERROR, MYF(0));
 
119
    DBUG_RETURN(TRUE);
 
120
  }
 
121
 
 
122
  DBUG_RETURN(FALSE);
 
123
}
 
124
 
 
125
 
 
126
/**
 
127
  Reconstructs interval expression from interval type and expression
 
128
  value that is in form of a value of the smalles entity:
 
129
  For
 
130
    YEAR_MONTH - expression is in months
 
131
    DAY_MINUTE - expression is in minutes
 
132
 
 
133
  SYNOPSIS
 
134
    Events::reconstruct_interval_expression()
 
135
      buf         Preallocated String buffer to add the value to
 
136
      interval    The interval type (for instance YEAR_MONTH)
 
137
      expression  The value in the lowest entity
 
138
 
 
139
  RETURN VALUE
 
140
    0  OK
 
141
    1  Error
 
142
*/
 
143
 
 
144
int
 
145
Events::reconstruct_interval_expression(String *buf, interval_type interval,
 
146
                                        longlong expression)
 
147
{
 
148
  ulonglong expr= expression;
 
149
  char tmp_buff[128], *end;
 
150
  bool close_quote= TRUE;
 
151
  int multipl= 0;
 
152
  char separator=':';
 
153
 
 
154
  switch (interval) {
 
155
  case INTERVAL_YEAR_MONTH:
 
156
    multipl= 12;
 
157
    separator= '-';
 
158
    goto common_1_lev_code;
 
159
  case INTERVAL_DAY_HOUR:
 
160
    multipl= 24;
 
161
    separator= ' ';
 
162
    goto common_1_lev_code;
 
163
  case INTERVAL_HOUR_MINUTE:
 
164
  case INTERVAL_MINUTE_SECOND:
 
165
    multipl= 60;
 
166
common_1_lev_code:
 
167
    buf->append('\'');
 
168
    end= longlong10_to_str(expression/multipl, tmp_buff, 10);
 
169
    buf->append(tmp_buff, (uint) (end- tmp_buff));
 
170
    expr= expr - (expr/multipl)*multipl;
 
171
    break;
 
172
  case INTERVAL_DAY_MINUTE:
 
173
  {
 
174
    ulonglong tmp_expr= expr;
 
175
 
 
176
    tmp_expr/=(24*60);
 
177
    buf->append('\'');
 
178
    end= longlong10_to_str(tmp_expr, tmp_buff, 10);
 
179
    buf->append(tmp_buff, (uint) (end- tmp_buff));// days
 
180
    buf->append(' ');
 
181
 
 
182
    tmp_expr= expr - tmp_expr*(24*60);//minutes left
 
183
    end= longlong10_to_str(tmp_expr/60, tmp_buff, 10);
 
184
    buf->append(tmp_buff, (uint) (end- tmp_buff));// hours
 
185
 
 
186
    expr= tmp_expr - (tmp_expr/60)*60;
 
187
    /* the code after the switch will finish */
 
188
  }
 
189
    break;
 
190
  case INTERVAL_HOUR_SECOND:
 
191
  {
 
192
    ulonglong tmp_expr= expr;
 
193
 
 
194
    buf->append('\'');
 
195
    end= longlong10_to_str(tmp_expr/3600, tmp_buff, 10);
 
196
    buf->append(tmp_buff, (uint) (end- tmp_buff));// hours
 
197
    buf->append(':');
 
198
 
 
199
    tmp_expr= tmp_expr - (tmp_expr/3600)*3600;
 
200
    end= longlong10_to_str(tmp_expr/60, tmp_buff, 10);
 
201
    buf->append(tmp_buff, (uint) (end- tmp_buff));// minutes
 
202
 
 
203
    expr= tmp_expr - (tmp_expr/60)*60;
 
204
    /* the code after the switch will finish */
 
205
  }
 
206
    break;
 
207
  case INTERVAL_DAY_SECOND:
 
208
  {
 
209
    ulonglong tmp_expr= expr;
 
210
 
 
211
    tmp_expr/=(24*3600);
 
212
    buf->append('\'');
 
213
    end= longlong10_to_str(tmp_expr, tmp_buff, 10);
 
214
    buf->append(tmp_buff, (uint) (end- tmp_buff));// days
 
215
    buf->append(' ');
 
216
 
 
217
    tmp_expr= expr - tmp_expr*(24*3600);//seconds left
 
218
    end= longlong10_to_str(tmp_expr/3600, tmp_buff, 10);
 
219
    buf->append(tmp_buff, (uint) (end- tmp_buff));// hours
 
220
    buf->append(':');
 
221
 
 
222
    tmp_expr= tmp_expr - (tmp_expr/3600)*3600;
 
223
    end= longlong10_to_str(tmp_expr/60, tmp_buff, 10);
 
224
    buf->append(tmp_buff, (uint) (end- tmp_buff));// minutes
 
225
 
 
226
    expr= tmp_expr - (tmp_expr/60)*60;
 
227
    /* the code after the switch will finish */
 
228
  }
 
229
    break;
 
230
  case INTERVAL_DAY_MICROSECOND:
 
231
  case INTERVAL_HOUR_MICROSECOND:
 
232
  case INTERVAL_MINUTE_MICROSECOND:
 
233
  case INTERVAL_SECOND_MICROSECOND:
 
234
  case INTERVAL_MICROSECOND:
 
235
    my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND");
 
236
    return 1;
 
237
  case INTERVAL_QUARTER:
 
238
    expr/= 3;
 
239
    close_quote= FALSE;
 
240
    break;
 
241
  case INTERVAL_WEEK:
 
242
    expr/= 7;
 
243
  default:
 
244
    close_quote= FALSE;
 
245
    break;
 
246
  }
 
247
  if (close_quote)
 
248
    buf->append(separator);
 
249
  end= longlong10_to_str(expr, tmp_buff, 10);
 
250
  buf->append(tmp_buff, (uint) (end- tmp_buff));
 
251
  if (close_quote)
 
252
    buf->append('\'');
 
253
 
 
254
  return 0;
 
255
}
 
256
 
 
257
 
 
258
/**
 
259
  Create a new query string for removing executable comments 
 
260
  for avoiding leak and keeping consistency of the execution 
 
261
  on master and slave.
 
262
  
 
263
  @param[in] thd                 Thread handler
 
264
  @param[in] buf                 Query string
 
265
 
 
266
  @return
 
267
             0           ok
 
268
             1           error
 
269
*/
 
270
static int
 
271
create_query_string(THD *thd, String *buf)
 
272
{
 
273
  /* Append the "CREATE" part of the query */
 
274
  if (buf->append(STRING_WITH_LEN("CREATE ")))
 
275
    return 1;
 
276
  /* Append definer */
 
277
  append_definer(thd, buf, &(thd->lex->definer->user), &(thd->lex->definer->host));
 
278
  /* Append the left part of thd->query after "DEFINER" part */
 
279
  if (buf->append(thd->lex->stmt_definition_begin,
 
280
                  thd->lex->stmt_definition_end -
 
281
                  thd->lex->stmt_definition_begin))
 
282
    return 1;
 
283
 
 
284
  return 0;
 
285
}
 
286
 
 
287
 
 
288
/**
 
289
  Create a new event.
 
290
 
 
291
  @param[in,out]  thd            THD
 
292
  @param[in]      parse_data     Event's data from parsing stage
 
293
  @param[in]      if_not_exists  Whether IF NOT EXISTS was
 
294
                                 specified
 
295
  In case there is an event with the same name (db) and
 
296
  IF NOT EXISTS is specified, an warning is put into the stack.
 
297
  @sa Events::drop_event for the notes about locking, pre-locking
 
298
  and Events DDL.
 
299
 
 
300
  @retval  FALSE  OK
 
301
  @retval  TRUE   Error (reported)
 
302
*/
 
303
 
 
304
bool
 
305
Events::create_event(THD *thd, Event_parse_data *parse_data,
 
306
                     bool if_not_exists)
 
307
{
 
308
  bool ret;
 
309
  bool save_binlog_row_based, event_already_exists;
 
310
  DBUG_ENTER("Events::create_event");
 
311
 
 
312
  if (check_if_system_tables_error())
 
313
    DBUG_RETURN(TRUE);
 
314
 
 
315
  /*
 
316
    Perform semantic checks outside of Event_db_repository:
 
317
    once CREATE EVENT is supported in prepared statements, the
 
318
    checks will be moved to PREPARE phase.
 
319
  */
 
320
  if (parse_data->check_parse_data(thd))
 
321
    DBUG_RETURN(TRUE);
 
322
 
 
323
  /* At create, one of them must be set */
 
324
  DBUG_ASSERT(parse_data->expression || parse_data->execute_at);
 
325
 
 
326
  if (check_access(thd, EVENT_ACL, parse_data->dbname.str, NULL, NULL, 0, 0))
 
327
    DBUG_RETURN(TRUE);
 
328
 
 
329
  if (check_db_dir_existence(parse_data->dbname.str))
 
330
  {
 
331
    my_error(ER_BAD_DB_ERROR, MYF(0), parse_data->dbname.str);
 
332
    DBUG_RETURN(TRUE);
 
333
  }
 
334
 
 
335
  if (parse_data->do_not_create)
 
336
    DBUG_RETURN(FALSE);
 
337
  /* 
 
338
    Turn off row binlogging of this statement and use statement-based 
 
339
    so that all supporting tables are updated for CREATE EVENT command.
 
340
  */
 
341
  if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
 
342
    thd->clear_current_stmt_binlog_format_row();
 
343
 
 
344
  if (lock_object_name(thd, MDL_key::EVENT,
 
345
                       parse_data->dbname.str, parse_data->name.str))
 
346
    DBUG_RETURN(TRUE);
 
347
 
 
348
  /* On error conditions my_error() is called so no need to handle here */
 
349
  if (!(ret= db_repository->create_event(thd, parse_data, if_not_exists,
 
350
                                         &event_already_exists)))
 
351
  {
 
352
    Event_queue_element *new_element;
 
353
    bool dropped= 0;
 
354
 
 
355
    if (!event_already_exists)
 
356
    {
 
357
      if (!(new_element= new Event_queue_element()))
 
358
        ret= TRUE;                                // OOM
 
359
      else if ((ret= db_repository->load_named_event(thd, parse_data->dbname,
 
360
                                                     parse_data->name,
 
361
                                                     new_element)))
 
362
      {
 
363
        if (!db_repository->drop_event(thd, parse_data->dbname,
 
364
                                       parse_data->name, TRUE))
 
365
          dropped= 1;
 
366
        delete new_element;
 
367
      }
 
368
      else
 
369
      {
 
370
        /* TODO: do not ignore the out parameter and a possible OOM error! */
 
371
        bool created;
 
372
        if (event_queue)
 
373
          event_queue->create_event(thd, new_element, &created);
 
374
      }
 
375
    }
 
376
    /*
 
377
      binlog the create event unless it's been successfully dropped
 
378
    */
 
379
    if (!dropped)
 
380
    {
 
381
      /* Binlog the create event. */
 
382
      DBUG_ASSERT(thd->query() && thd->query_length());
 
383
      String log_query;
 
384
      if (create_query_string(thd, &log_query))
 
385
      {
 
386
        sql_print_error("Event Error: An error occurred while creating query "
 
387
                        "string, before writing it into binary log.");
 
388
        ret= true;
 
389
      }
 
390
      else
 
391
      {
 
392
        /*
 
393
          If the definer is not set or set to CURRENT_USER, the value
 
394
          of CURRENT_USER will be written into the binary log as the
 
395
          definer for the SQL thread.
 
396
        */
 
397
        ret= write_bin_log(thd, TRUE, log_query.ptr(), log_query.length());
 
398
      }
 
399
    }
 
400
  }
 
401
  /* Restore the state of binlog format */
 
402
  DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
 
403
  if (save_binlog_row_based)
 
404
    thd->set_current_stmt_binlog_format_row();
 
405
 
 
406
  DBUG_RETURN(ret);
 
407
}
 
408
 
 
409
 
 
410
/**
 
411
  Alter an event.
 
412
 
 
413
  @param[in,out] thd         THD
 
414
  @param[in]     parse_data  Event's data from parsing stage
 
415
  @param[in]     new_dbname  A new schema name for the event. Set in the case of
 
416
                             ALTER EVENT RENAME, otherwise is NULL.
 
417
  @param[in]     new_name    A new name for the event. Set in the case of
 
418
                             ALTER EVENT RENAME
 
419
 
 
420
  Parameter 'et' contains data about dbname and event name.
 
421
  Parameter 'new_name' is the new name of the event, if not null
 
422
  this means that RENAME TO was specified in the query
 
423
  @sa Events::drop_event for the locking notes.
 
424
 
 
425
  @retval  FALSE  OK
 
426
  @retval  TRUE   error (reported)
 
427
*/
 
428
 
 
429
bool
 
430
Events::update_event(THD *thd, Event_parse_data *parse_data,
 
431
                     LEX_STRING *new_dbname, LEX_STRING *new_name)
 
432
{
 
433
  int ret;
 
434
  bool save_binlog_row_based;
 
435
  Event_queue_element *new_element;
 
436
 
 
437
  DBUG_ENTER("Events::update_event");
 
438
 
 
439
  if (check_if_system_tables_error())
 
440
    DBUG_RETURN(TRUE);
 
441
 
 
442
  if (parse_data->check_parse_data(thd) || parse_data->do_not_create)
 
443
    DBUG_RETURN(TRUE);
 
444
 
 
445
  if (check_access(thd, EVENT_ACL, parse_data->dbname.str, NULL, NULL, 0, 0))
 
446
    DBUG_RETURN(TRUE);
 
447
 
 
448
  if (new_dbname)                               /* It's a rename */
 
449
  {
 
450
    /* Check that the new and the old names differ. */
 
451
    if ( !sortcmp_lex_string(parse_data->dbname, *new_dbname,
 
452
                             system_charset_info) &&
 
453
         !sortcmp_lex_string(parse_data->name, *new_name,
 
454
                             system_charset_info))
 
455
    {
 
456
      my_error(ER_EVENT_SAME_NAME, MYF(0));
 
457
      DBUG_RETURN(TRUE);
 
458
    }
 
459
 
 
460
    /*
 
461
      And the user has sufficient privileges to use the target database.
 
462
      Do it before checking whether the database exists: we don't want
 
463
      to tell the user that a database doesn't exist if they can not
 
464
      access it.
 
465
    */
 
466
    if (check_access(thd, EVENT_ACL, new_dbname->str, NULL, NULL, 0, 0))
 
467
      DBUG_RETURN(TRUE);
 
468
 
 
469
    /* Check that the target database exists */
 
470
    if (check_db_dir_existence(new_dbname->str))
 
471
    {
 
472
      my_error(ER_BAD_DB_ERROR, MYF(0), new_dbname->str);
 
473
      DBUG_RETURN(TRUE);
 
474
    }
 
475
  }
 
476
 
 
477
  /* 
 
478
    Turn off row binlogging of this statement and use statement-based 
 
479
    so that all supporting tables are updated for UPDATE EVENT command.
 
480
  */
 
481
  if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
 
482
    thd->clear_current_stmt_binlog_format_row();
 
483
 
 
484
  if (lock_object_name(thd, MDL_key::EVENT,
 
485
                       parse_data->dbname.str, parse_data->name.str))
 
486
    DBUG_RETURN(TRUE);
 
487
 
 
488
  /* On error conditions my_error() is called so no need to handle here */
 
489
  if (!(ret= db_repository->update_event(thd, parse_data,
 
490
                                         new_dbname, new_name)))
 
491
  {
 
492
    LEX_STRING dbname= new_dbname ? *new_dbname : parse_data->dbname;
 
493
    LEX_STRING name= new_name ? *new_name : parse_data->name;
 
494
 
 
495
    if (!(new_element= new Event_queue_element()))
 
496
      ret= TRUE;                                // OOM
 
497
    else if ((ret= db_repository->load_named_event(thd, dbname, name,
 
498
                                                   new_element)))
 
499
      delete new_element;
 
500
    else
 
501
    {
 
502
      /*
 
503
        TODO: check if an update actually has inserted an entry
 
504
        into the queue.
 
505
        If not, and the element is ON COMPLETION NOT PRESERVE, delete
 
506
        it right away.
 
507
      */
 
508
      if (event_queue)
 
509
        event_queue->update_event(thd, parse_data->dbname, parse_data->name,
 
510
                                  new_element);
 
511
      /* Binlog the alter event. */
 
512
      DBUG_ASSERT(thd->query() && thd->query_length());
 
513
      ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
 
514
    }
 
515
  }
 
516
  /* Restore the state of binlog format */
 
517
  DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
 
518
  if (save_binlog_row_based)
 
519
    thd->set_current_stmt_binlog_format_row();
 
520
 
 
521
  DBUG_RETURN(ret);
 
522
}
 
523
 
 
524
 
 
525
/**
 
526
  Drops an event
 
527
 
 
528
  @param[in,out]  thd        THD
 
529
  @param[in]      dbname     Event's schema
 
530
  @param[in]      name       Event's name
 
531
  @param[in]      if_exists  When this is set and the event does not exist
 
532
                             a warning is pushed into the warning stack.
 
533
                             Otherwise the operation produces an error.
 
534
 
 
535
  @note Similarly to DROP PROCEDURE, we do not allow DROP EVENT
 
536
  under LOCK TABLES mode, unless table mysql.event is locked.  To
 
537
  ensure that, we do not reset & backup the open tables state in
 
538
  this function - if in LOCK TABLES or pre-locking mode, this will
 
539
  lead to an error 'Table mysql.event is not locked with LOCK
 
540
  TABLES' unless it _is_ locked. In pre-locked mode there is
 
541
  another barrier - DROP EVENT commits the current transaction,
 
542
  and COMMIT/ROLLBACK is not allowed in stored functions and
 
543
  triggers.
 
544
 
 
545
  @retval  FALSE  OK
 
546
  @retval  TRUE   Error (reported)
 
547
*/
 
548
 
 
549
bool
 
550
Events::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name, bool if_exists)
 
551
{
 
552
  int ret;
 
553
  bool save_binlog_row_based;
 
554
  DBUG_ENTER("Events::drop_event");
 
555
 
 
556
  if (check_if_system_tables_error())
 
557
    DBUG_RETURN(TRUE);
 
558
 
 
559
  if (check_access(thd, EVENT_ACL, dbname.str, NULL, NULL, 0, 0))
 
560
    DBUG_RETURN(TRUE);
 
561
 
 
562
  /*
 
563
    Turn off row binlogging of this statement and use statement-based so
 
564
    that all supporting tables are updated for DROP EVENT command.
 
565
  */
 
566
  if ((save_binlog_row_based= thd->is_current_stmt_binlog_format_row()))
 
567
    thd->clear_current_stmt_binlog_format_row();
 
568
 
 
569
  if (lock_object_name(thd, MDL_key::EVENT,
 
570
                       dbname.str, name.str))
 
571
    DBUG_RETURN(TRUE);
 
572
  /* On error conditions my_error() is called so no need to handle here */
 
573
  if (!(ret= db_repository->drop_event(thd, dbname, name, if_exists)))
 
574
  {
 
575
    if (event_queue)
 
576
      event_queue->drop_event(thd, dbname, name);
 
577
    /* Binlog the drop event. */
 
578
    DBUG_ASSERT(thd->query() && thd->query_length());
 
579
    ret= write_bin_log(thd, TRUE, thd->query(), thd->query_length());
 
580
  }
 
581
  /* Restore the state of binlog format */
 
582
  DBUG_ASSERT(!thd->is_current_stmt_binlog_format_row());
 
583
  if (save_binlog_row_based)
 
584
    thd->set_current_stmt_binlog_format_row();
 
585
  DBUG_RETURN(ret);
 
586
}
 
587
 
 
588
 
 
589
/**
 
590
  Drops all events from a schema
 
591
 
 
592
  @note We allow to drop all events in a schema even if the
 
593
  scheduler is disabled. This is to not produce any warnings
 
594
  in case of DROP DATABASE and a disabled scheduler.
 
595
 
 
596
  @param[in,out]  thd  Thread
 
597
  @param[in]      db   ASCIIZ schema name
 
598
*/
 
599
 
 
600
void
 
601
Events::drop_schema_events(THD *thd, char *db)
 
602
{
 
603
  LEX_STRING const db_lex= { db, strlen(db) };
 
604
 
 
605
  DBUG_ENTER("Events::drop_schema_events");
 
606
  DBUG_PRINT("enter", ("dropping events from %s", db));
 
607
 
 
608
  /*
 
609
    Sic: no check if the scheduler is disabled or system tables
 
610
    are damaged, as intended.
 
611
  */
 
612
  if (event_queue)
 
613
    event_queue->drop_schema_events(thd, db_lex);
 
614
  db_repository->drop_schema_events(thd, db_lex);
 
615
 
 
616
  DBUG_VOID_RETURN;
 
617
}
 
618
 
 
619
 
 
620
/**
 
621
  A helper function to generate SHOW CREATE EVENT output from
 
622
  a named event
 
623
*/
 
624
 
 
625
static bool
 
626
send_show_create_event(THD *thd, Event_timed *et, Protocol *protocol)
 
627
{
 
628
  char show_str_buf[10 * STRING_BUFFER_USUAL_SIZE];
 
629
  String show_str(show_str_buf, sizeof(show_str_buf), system_charset_info);
 
630
  List<Item> field_list;
 
631
  LEX_STRING sql_mode;
 
632
  const String *tz_name;
 
633
 
 
634
  DBUG_ENTER("send_show_create_event");
 
635
 
 
636
  show_str.length(0);
 
637
  if (et->get_create_event(thd, &show_str))
 
638
    DBUG_RETURN(TRUE);
 
639
 
 
640
  field_list.push_back(new Item_empty_string("Event", NAME_CHAR_LEN));
 
641
 
 
642
  if (sql_mode_string_representation(thd, et->sql_mode, &sql_mode))
 
643
    DBUG_RETURN(TRUE);
 
644
 
 
645
  field_list.push_back(new Item_empty_string("sql_mode", (uint) sql_mode.length));
 
646
 
 
647
  tz_name= et->time_zone->get_name();
 
648
 
 
649
  field_list.push_back(new Item_empty_string("time_zone",
 
650
                                             tz_name->length()));
 
651
 
 
652
  field_list.push_back(new Item_empty_string("Create Event",
 
653
                                             show_str.length()));
 
654
 
 
655
  field_list.push_back(
 
656
    new Item_empty_string("character_set_client", MY_CS_NAME_SIZE));
 
657
 
 
658
  field_list.push_back(
 
659
    new Item_empty_string("collation_connection", MY_CS_NAME_SIZE));
 
660
 
 
661
  field_list.push_back(
 
662
    new Item_empty_string("Database Collation", MY_CS_NAME_SIZE));
 
663
 
 
664
  if (protocol->send_result_set_metadata(&field_list,
 
665
                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
 
666
    DBUG_RETURN(TRUE);
 
667
 
 
668
  protocol->prepare_for_resend();
 
669
 
 
670
  protocol->store(et->name.str, et->name.length, system_charset_info);
 
671
  protocol->store(sql_mode.str, sql_mode.length, system_charset_info);
 
672
  protocol->store(tz_name->ptr(), tz_name->length(), system_charset_info);
 
673
  protocol->store(show_str.ptr(), show_str.length(),
 
674
                  et->creation_ctx->get_client_cs());
 
675
  protocol->store(et->creation_ctx->get_client_cs()->csname,
 
676
                  strlen(et->creation_ctx->get_client_cs()->csname),
 
677
                  system_charset_info);
 
678
  protocol->store(et->creation_ctx->get_connection_cl()->name,
 
679
                  strlen(et->creation_ctx->get_connection_cl()->name),
 
680
                  system_charset_info);
 
681
  protocol->store(et->creation_ctx->get_db_cl()->name,
 
682
                  strlen(et->creation_ctx->get_db_cl()->name),
 
683
                  system_charset_info);
 
684
 
 
685
  if (protocol->write())
 
686
    DBUG_RETURN(TRUE);
 
687
 
 
688
  my_eof(thd);
 
689
 
 
690
  DBUG_RETURN(FALSE);
 
691
}
 
692
 
 
693
 
 
694
/**
 
695
  Implement SHOW CREATE EVENT statement
 
696
 
 
697
      thd   Thread context
 
698
      spn   The name of the event (db, name)
 
699
 
 
700
  @retval  FALSE  OK
 
701
  @retval  TRUE   error (reported)
 
702
*/
 
703
 
 
704
bool
 
705
Events::show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
 
706
{
 
707
  Event_timed et;
 
708
  bool ret;
 
709
 
 
710
  DBUG_ENTER("Events::show_create_event");
 
711
  DBUG_PRINT("enter", ("name: %s@%s", dbname.str, name.str));
 
712
 
 
713
  if (check_if_system_tables_error())
 
714
    DBUG_RETURN(TRUE);
 
715
 
 
716
  if (check_access(thd, EVENT_ACL, dbname.str, NULL, NULL, 0, 0))
 
717
    DBUG_RETURN(TRUE);
 
718
 
 
719
  /*
 
720
    We would like to allow SHOW CREATE EVENT under LOCK TABLES and
 
721
    in pre-locked mode. mysql.event table is marked as a system table.
 
722
    This flag reduces the set of its participation scenarios in LOCK TABLES
 
723
    operation, and therefore an out-of-bound open of this table
 
724
    for reading like the one below (sic, only for reading) is
 
725
    more or less deadlock-free. For additional information about when a
 
726
    deadlock can occur please refer to the description of 'system table'
 
727
    flag.
 
728
  */
 
729
  ret= db_repository->load_named_event(thd, dbname, name, &et);
 
730
 
 
731
  if (!ret)
 
732
    ret= send_show_create_event(thd, &et, thd->protocol);
 
733
 
 
734
  DBUG_RETURN(ret);
 
735
}
 
736
 
 
737
 
 
738
/**
 
739
  Check access rights and fill INFORMATION_SCHEMA.events table.
 
740
 
 
741
  @param[in,out]  thd     Thread context
 
742
  @param[in]      tables  The temporary table to fill.
 
743
 
 
744
  In MySQL INFORMATION_SCHEMA tables are temporary tables that are
 
745
  created and filled on demand. In this function, we fill
 
746
  INFORMATION_SCHEMA.events. It is a callback for I_S module, invoked from
 
747
  sql_show.cc
 
748
 
 
749
  @return Has to be integer, as such is the requirement of the I_S API
 
750
  @retval  0  success
 
751
  @retval  1  an error, pushed into the error stack
 
752
*/
 
753
 
 
754
int
 
755
Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
 
756
{
 
757
  char *db= NULL;
 
758
  int ret;
 
759
  DBUG_ENTER("Events::fill_schema_events");
 
760
 
 
761
  if (check_if_system_tables_error())
 
762
    DBUG_RETURN(1);
 
763
 
 
764
  /*
 
765
    If it's SHOW EVENTS then thd->lex->select_lex.db is guaranteed not to
 
766
    be NULL. Let's do an assert anyway.
 
767
  */
 
768
  if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS)
 
769
  {
 
770
    DBUG_ASSERT(thd->lex->select_lex.db);
 
771
    if (!is_infoschema_db(thd->lex->select_lex.db) && // There is no events in I_S
 
772
        check_access(thd, EVENT_ACL, thd->lex->select_lex.db,
 
773
                     NULL, NULL, 0, 0))
 
774
      DBUG_RETURN(1);
 
775
    db= thd->lex->select_lex.db;
 
776
  }
 
777
  ret= db_repository->fill_schema_events(thd, tables, db);
 
778
 
 
779
  DBUG_RETURN(ret);
 
780
}
 
781
 
 
782
 
 
783
/**
 
784
  Initializes the scheduler's structures.
 
785
 
 
786
  @param  opt_noacl_or_bootstrap
 
787
                     TRUE if there is --skip-grant-tables or --bootstrap
 
788
                     option. In that case we disable the event scheduler.
 
789
 
 
790
  @note   This function is not synchronized.
 
791
 
 
792
  @retval  FALSE   Perhaps there was an error, and the event scheduler
 
793
                   is disabled. But the error is not fatal and the 
 
794
                   server start up can continue.
 
795
  @retval  TRUE    Fatal error. Startup must terminate (call unireg_abort()).
 
796
*/
 
797
 
 
798
bool
 
799
Events::init(bool opt_noacl_or_bootstrap)
 
800
{
 
801
 
 
802
  THD *thd;
 
803
  bool res= FALSE;
 
804
 
 
805
  DBUG_ENTER("Events::init");
 
806
 
 
807
  /* We need a temporary THD during boot */
 
808
  if (!(thd= new THD()))
 
809
  {
 
810
    res= TRUE;
 
811
    goto end;
 
812
  }
 
813
  /*
 
814
    The thread stack does not start from this function but we cannot
 
815
    guess the real value. So better some value that doesn't assert than
 
816
    no value.
 
817
  */
 
818
  thd->thread_stack= (char*) &thd;
 
819
  thd->store_globals();
 
820
 
 
821
  /*
 
822
    We will need Event_db_repository anyway, even if the scheduler is
 
823
    disabled - to perform events DDL.
 
824
  */
 
825
  if (!(db_repository= new Event_db_repository))
 
826
  {
 
827
    res= TRUE; /* fatal error: request unireg_abort */
 
828
    goto end;
 
829
  }
 
830
 
 
831
  /*
 
832
    Since we allow event DDL even if the scheduler is disabled,
 
833
    check the system tables, as we might need them.
 
834
 
 
835
    If run with --skip-grant-tables or --bootstrap, don't try to do the
 
836
    check of system tables and don't complain: in these modes the tables
 
837
    are most likely not there and we're going to disable the event
 
838
    scheduler anyway.
 
839
  */
 
840
  if (opt_noacl_or_bootstrap || Event_db_repository::check_system_tables(thd))
 
841
  {
 
842
    if (! opt_noacl_or_bootstrap)
 
843
    {
 
844
      sql_print_error("Event Scheduler: An error occurred when initializing "
 
845
                      "system tables. Disabling the Event Scheduler.");
 
846
      check_system_tables_error= TRUE;
 
847
    }
 
848
 
 
849
    /* Disable the scheduler since the system tables are not up to date */
 
850
    opt_event_scheduler= EVENTS_DISABLED;
 
851
    goto end;
 
852
  }
 
853
 
 
854
  /*
 
855
    Was disabled explicitly from the command line, or because we're running
 
856
    with --skip-grant-tables, or --bootstrap, or because we have no system
 
857
    tables.
 
858
  */
 
859
  if (opt_event_scheduler == Events::EVENTS_DISABLED)
 
860
    goto end;
 
861
 
 
862
 
 
863
  DBUG_ASSERT(opt_event_scheduler == Events::EVENTS_ON ||
 
864
              opt_event_scheduler == Events::EVENTS_OFF);
 
865
 
 
866
  if (!(event_queue= new Event_queue) ||
 
867
      !(scheduler= new Event_scheduler(event_queue)))
 
868
  {
 
869
    res= TRUE; /* fatal error: request unireg_abort */
 
870
    goto end;
 
871
  }
 
872
 
 
873
  if (event_queue->init_queue(thd) || load_events_from_db(thd) ||
 
874
      (opt_event_scheduler == EVENTS_ON && scheduler->start()))
 
875
  {
 
876
    sql_print_error("Event Scheduler: Error while loading from disk.");
 
877
    res= TRUE; /* fatal error: request unireg_abort */
 
878
    goto end;
 
879
  }
 
880
  Event_worker_thread::init(db_repository);
 
881
 
 
882
end:
 
883
  if (res)
 
884
  {
 
885
    delete db_repository;
 
886
    delete event_queue;
 
887
    delete scheduler;
 
888
  }
 
889
  delete thd;
 
890
  /* Remember that we don't have a THD */
 
891
  my_pthread_setspecific_ptr(THR_THD,  NULL);
 
892
 
 
893
  DBUG_RETURN(res);
 
894
}
 
895
 
 
896
/*
 
897
  Cleans up scheduler's resources. Called at server shutdown.
 
898
 
 
899
  SYNOPSIS
 
900
    Events::deinit()
 
901
 
 
902
  NOTES
 
903
    This function is not synchronized.
 
904
*/
 
905
 
 
906
void
 
907
Events::deinit()
 
908
{
 
909
  DBUG_ENTER("Events::deinit");
 
910
 
 
911
  if (opt_event_scheduler != EVENTS_DISABLED)
 
912
  {
 
913
    delete scheduler;
 
914
    scheduler= NULL;                            /* safety */
 
915
    delete event_queue;
 
916
    event_queue= NULL;                          /* safety */
 
917
  }
 
918
 
 
919
  delete db_repository;
 
920
  db_repository= NULL;                          /* safety */
 
921
 
 
922
  DBUG_VOID_RETURN;
 
923
}
 
924
 
 
925
#ifdef HAVE_PSI_INTERFACE
 
926
PSI_mutex_key key_LOCK_event_queue,
 
927
              key_event_scheduler_LOCK_scheduler_state;
 
928
 
 
929
static PSI_mutex_info all_events_mutexes[]=
 
930
{
 
931
  { &key_LOCK_event_queue, "LOCK_event_queue", PSI_FLAG_GLOBAL},
 
932
  { &key_event_scheduler_LOCK_scheduler_state, "Event_scheduler::LOCK_scheduler_state", PSI_FLAG_GLOBAL}
 
933
};
 
934
 
 
935
PSI_cond_key key_event_scheduler_COND_state, key_COND_queue_state;
 
936
 
 
937
static PSI_cond_info all_events_conds[]=
 
938
{
 
939
  { &key_event_scheduler_COND_state, "Event_scheduler::COND_state", PSI_FLAG_GLOBAL},
 
940
  { &key_COND_queue_state, "COND_queue_state", PSI_FLAG_GLOBAL},
 
941
};
 
942
 
 
943
PSI_thread_key key_thread_event_scheduler, key_thread_event_worker;
 
944
 
 
945
static PSI_thread_info all_events_threads[]=
 
946
{
 
947
  { &key_thread_event_scheduler, "event_scheduler", PSI_FLAG_GLOBAL},
 
948
  { &key_thread_event_worker, "event_worker", 0}
 
949
};
 
950
 
 
951
static void init_events_psi_keys(void)
 
952
{
 
953
  const char* category= "sql";
 
954
  int count;
 
955
 
 
956
  if (PSI_server == NULL)
 
957
    return;
 
958
 
 
959
  count= array_elements(all_events_mutexes);
 
960
  PSI_server->register_mutex(category, all_events_mutexes, count);
 
961
 
 
962
  count= array_elements(all_events_conds);
 
963
  PSI_server->register_cond(category, all_events_conds, count);
 
964
 
 
965
  count= array_elements(all_events_threads);
 
966
  PSI_server->register_thread(category, all_events_threads, count);
 
967
}
 
968
#endif /* HAVE_PSI_INTERFACE */
 
969
 
 
970
/**
 
971
  Inits Events mutexes
 
972
 
 
973
  SYNOPSIS
 
974
    Events::init_mutexes()
 
975
      thd  Thread
 
976
*/
 
977
 
 
978
void
 
979
Events::init_mutexes()
 
980
{
 
981
#ifdef HAVE_PSI_INTERFACE
 
982
  init_events_psi_keys();
 
983
#endif
 
984
}
 
985
 
 
986
 
 
987
/*
 
988
  Dumps the internal status of the scheduler and the memory cache
 
989
  into a table with two columns - Name & Value. Different properties
 
990
  which could be useful for debugging for instance deadlocks are
 
991
  returned.
 
992
 
 
993
  SYNOPSIS
 
994
    Events::dump_internal_status()
 
995
*/
 
996
 
 
997
void
 
998
Events::dump_internal_status()
 
999
{
 
1000
  DBUG_ENTER("Events::dump_internal_status");
 
1001
  puts("\n\n\nEvents status:");
 
1002
  puts("LLA = Last Locked At  LUA = Last Unlocked At");
 
1003
  puts("WOC = Waiting On Condition  DL = Data Locked");
 
1004
 
 
1005
  /*
 
1006
    opt_event_scheduler should only be accessed while
 
1007
    holding LOCK_global_system_variables.
 
1008
  */
 
1009
  mysql_mutex_lock(&LOCK_global_system_variables);
 
1010
  if (opt_event_scheduler == EVENTS_DISABLED)
 
1011
    puts("The Event Scheduler is disabled");
 
1012
  else
 
1013
  {
 
1014
    scheduler->dump_internal_status();
 
1015
    event_queue->dump_internal_status();
 
1016
  }
 
1017
 
 
1018
  mysql_mutex_unlock(&LOCK_global_system_variables);
 
1019
  DBUG_VOID_RETURN;
 
1020
}
 
1021
 
 
1022
bool Events::start()
 
1023
{
 
1024
  return scheduler->start();
 
1025
}
 
1026
 
 
1027
bool Events::stop()
 
1028
{
 
1029
  return scheduler->stop();
 
1030
}
 
1031
 
 
1032
/**
 
1033
  Loads all ENABLED events from mysql.event into a prioritized
 
1034
  queue.
 
1035
 
 
1036
  This function is called during the server start up. It reads
 
1037
  every event, computes the next execution time, and if the event
 
1038
  needs execution, adds it to a prioritized queue. Otherwise, if
 
1039
  ON COMPLETION DROP is specified, the event is automatically
 
1040
  removed from the table.
 
1041
 
 
1042
  @param[in,out] thd Thread context. Used for memory allocation in some cases.
 
1043
 
 
1044
  @retval  FALSE  success
 
1045
  @retval  TRUE   error, the load is aborted
 
1046
 
 
1047
  @note Reports the error to the console
 
1048
*/
 
1049
 
 
1050
bool
 
1051
Events::load_events_from_db(THD *thd)
 
1052
{
 
1053
  TABLE *table;
 
1054
  READ_RECORD read_record_info;
 
1055
  bool ret= TRUE;
 
1056
  uint count= 0;
 
1057
  ulong saved_master_access;
 
1058
 
 
1059
  DBUG_ENTER("Events::load_events_from_db");
 
1060
  DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
 
1061
 
 
1062
  /*
 
1063
    NOTE: even if we run in read-only mode, we should be able to lock the
 
1064
    mysql.event table for writing. In order to achieve this, we should call
 
1065
    mysql_lock_tables() under the super user.
 
1066
  */
 
1067
 
 
1068
  saved_master_access= thd->security_ctx->master_access;
 
1069
  thd->security_ctx->master_access |= SUPER_ACL;
 
1070
 
 
1071
  ret= db_repository->open_event_table(thd, TL_WRITE, &table);
 
1072
 
 
1073
  thd->security_ctx->master_access= saved_master_access;
 
1074
 
 
1075
  if (ret)
 
1076
  {
 
1077
    sql_print_error("Event Scheduler: Failed to open table mysql.event");
 
1078
    DBUG_RETURN(TRUE);
 
1079
  }
 
1080
 
 
1081
  if (init_read_record(&read_record_info, thd, table, NULL, 0, 1, FALSE))
 
1082
  {
 
1083
    close_thread_tables(thd);
 
1084
    DBUG_RETURN(TRUE);
 
1085
  }
 
1086
 
 
1087
  while (!(read_record_info.read_record(&read_record_info)))
 
1088
  {
 
1089
    Event_queue_element *et;
 
1090
    bool created;
 
1091
    bool drop_on_completion;
 
1092
 
 
1093
    if (!(et= new Event_queue_element))
 
1094
      goto end;
 
1095
 
 
1096
    DBUG_PRINT("info", ("Loading event from row."));
 
1097
 
 
1098
    if (et->load_from_row(thd, table))
 
1099
    {
 
1100
      sql_print_error("Event Scheduler: "
 
1101
                      "Error while loading events from mysql.event. "
 
1102
                      "The table probably contains bad data or is corrupted");
 
1103
      delete et;
 
1104
      goto end;
 
1105
    }
 
1106
    drop_on_completion= (et->on_completion ==
 
1107
                         Event_parse_data::ON_COMPLETION_DROP);
 
1108
 
 
1109
 
 
1110
    if (event_queue->create_event(thd, et, &created))
 
1111
    {
 
1112
      /* Out of memory */
 
1113
      delete et;
 
1114
      goto end;
 
1115
    }
 
1116
    if (created)
 
1117
      count++;
 
1118
    else if (drop_on_completion)
 
1119
    {
 
1120
      /*
 
1121
        If not created, a stale event - drop if immediately if
 
1122
        ON COMPLETION NOT PRESERVE.
 
1123
        XXX: This won't be replicated, thus the drop won't appear in
 
1124
             in the slave. When the slave is restarted it will drop events.
 
1125
             However, as the slave will be "out of sync", it might happen that
 
1126
             an event created on the master, after master restart, won't be
 
1127
             replicated to the slave correctly, as the create will fail there.
 
1128
      */
 
1129
      int rc= table->file->ha_delete_row(table->record[0]);
 
1130
      if (rc)
 
1131
      {
 
1132
        table->file->print_error(rc, MYF(0));
 
1133
        goto end;
 
1134
      }
 
1135
    }
 
1136
  }
 
1137
  if (global_system_variables.log_warnings)
 
1138
    sql_print_information("Event Scheduler: Loaded %d event%s",
 
1139
                          count, (count == 1) ? "" : "s");
 
1140
  ret= FALSE;
 
1141
 
 
1142
end:
 
1143
  end_read_record(&read_record_info);
 
1144
 
 
1145
  close_mysql_tables(thd);
 
1146
  DBUG_RETURN(ret);
 
1147
}
 
1148
 
 
1149
/**
 
1150
  @} (End of group Event_Scheduler)
 
1151
*/