~ubuntu-branches/ubuntu/precise/mysql-5.1/precise

« back to all changes in this revision

Viewing changes to sql/event_db_repository.cc

  • Committer: Bazaar Package Importer
  • Author(s): Norbert Tretkowski
  • Date: 2010-03-17 14:56:02 UTC
  • Revision ID: james.westby@ubuntu.com-20100317145602-x7e30l1b2sb5s6w6
Tags: upstream-5.1.45
ImportĀ upstreamĀ versionĀ 5.1.45

Show diffs side-by-side

added added

removed removed

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