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