00001 /* Copyright (C) 2004-2006 MySQL AB 00002 00003 This program is free software; you can redistribute it and/or modify 00004 it under the terms of the GNU General Public License as published by 00005 the Free Software Foundation; either version 2 of the License, or 00006 (at your option) any later version. 00007 00008 This program is distributed in the hope that it will be useful, 00009 but WITHOUT ANY WARRANTY; without even the implied warranty of 00010 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00011 GNU General Public License for more details. 00012 00013 You should have received a copy of the GNU General Public License 00014 along with this program; if not, write to the Free Software 00015 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ 00016 00017 #include "mysql_priv.h" 00018 #include "events_priv.h" 00019 #include "events.h" 00020 #include "event_timed.h" 00021 #include "event_scheduler.h" 00022 #include "sp.h" 00023 #include "sp_head.h" 00024 00025 /* 00026 TODO list : 00027 - CREATE EVENT should not go into binary log! Does it now? The SQL statements 00028 issued by the EVENT are replicated. 00029 I have an idea how to solve the problem at failover. So the status field 00030 will be ENUM('DISABLED', 'ENABLED', 'SLAVESIDE_DISABLED'). 00031 In this case when CREATE EVENT is replicated it should go into the binary 00032 as SLAVESIDE_DISABLED if it is ENABLED, when it's created as DISABLEd it 00033 should be replicated as disabled. If an event is ALTERed as DISABLED the 00034 query should go untouched into the binary log, when ALTERed as enable then 00035 it should go as SLAVESIDE_DISABLED. This is regarding the SQL interface. 00036 TT routines however modify mysql.event internally and this does not go the 00037 log so in this case queries has to be injected into the log...somehow... or 00038 maybe a solution is RBR for this case, because the event may go only from 00039 ENABLED to DISABLED status change and this is safe for replicating. As well 00040 an event may be deleted which is also safe for RBR. 00041 00042 - Add logging to file 00043 00044 Warning: 00045 - For now parallel execution is not possible because the same sp_head cannot 00046 be executed few times!!! There is still no lock attached to particular 00047 event. 00048 */ 00049 00050 00051 MEM_ROOT evex_mem_root; 00052 time_t mysql_event_last_create_time= 0L; 00053 00054 00055 const char *event_scheduler_state_names[]= 00056 { "OFF", "0", "ON", "1", "SUSPEND", "2", NullS }; 00057 00058 TYPELIB Events::opt_typelib= 00059 { 00060 array_elements(event_scheduler_state_names)-1, 00061 "", 00062 event_scheduler_state_names, 00063 NULL 00064 }; 00065 00066 00067 ulong Events::opt_event_scheduler= 2; 00068 00069 static 00070 TABLE_FIELD_W_TYPE event_table_fields[Events::FIELD_COUNT] = { 00071 { 00072 {(char *) STRING_WITH_LEN("db")}, 00073 {(char *) STRING_WITH_LEN("char(64)")}, 00074 {(char *) STRING_WITH_LEN("utf8")} 00075 }, 00076 { 00077 {(char *) STRING_WITH_LEN("name")}, 00078 {(char *) STRING_WITH_LEN("char(64)")}, 00079 {(char *) STRING_WITH_LEN("utf8")} 00080 }, 00081 { 00082 {(char *) STRING_WITH_LEN("body")}, 00083 {(char *) STRING_WITH_LEN("longblob")}, 00084 {NULL, 0} 00085 }, 00086 { 00087 {(char *) STRING_WITH_LEN("definer")}, 00088 {(char *) STRING_WITH_LEN("char(77)")}, 00089 {(char *) STRING_WITH_LEN("utf8")} 00090 }, 00091 { 00092 {(char *) STRING_WITH_LEN("execute_at")}, 00093 {(char *) STRING_WITH_LEN("datetime")}, 00094 {NULL, 0} 00095 }, 00096 { 00097 {(char *) STRING_WITH_LEN("interval_value")}, 00098 {(char *) STRING_WITH_LEN("int(11)")}, 00099 {NULL, 0} 00100 }, 00101 { 00102 {(char *) STRING_WITH_LEN("interval_field")}, 00103 {(char *) STRING_WITH_LEN("enum('YEAR','QUARTER','MONTH','DAY'," 00104 "'HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR'," 00105 "'DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND'," 00106 "'DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND'," 00107 "'SECOND_MICROSECOND')")}, 00108 {NULL, 0} 00109 }, 00110 { 00111 {(char *) STRING_WITH_LEN("created")}, 00112 {(char *) STRING_WITH_LEN("timestamp")}, 00113 {NULL, 0} 00114 }, 00115 { 00116 {(char *) STRING_WITH_LEN("modified")}, 00117 {(char *) STRING_WITH_LEN("timestamp")}, 00118 {NULL, 0} 00119 }, 00120 { 00121 {(char *) STRING_WITH_LEN("last_executed")}, 00122 {(char *) STRING_WITH_LEN("datetime")}, 00123 {NULL, 0} 00124 }, 00125 { 00126 {(char *) STRING_WITH_LEN("starts")}, 00127 {(char *) STRING_WITH_LEN("datetime")}, 00128 {NULL, 0} 00129 }, 00130 { 00131 {(char *) STRING_WITH_LEN("ends")}, 00132 {(char *) STRING_WITH_LEN("datetime")}, 00133 {NULL, 0} 00134 }, 00135 { 00136 {(char *) STRING_WITH_LEN("status")}, 00137 {(char *) STRING_WITH_LEN("enum('ENABLED','DISABLED')")}, 00138 {NULL, 0} 00139 }, 00140 { 00141 {(char *) STRING_WITH_LEN("on_completion")}, 00142 {(char *) STRING_WITH_LEN("enum('DROP','PRESERVE')")}, 00143 {NULL, 0} 00144 }, 00145 { 00146 {(char *) STRING_WITH_LEN("sql_mode")}, 00147 {(char *) STRING_WITH_LEN("set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES'," 00148 "'IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION'," 00149 "'NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB'," 00150 "'NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40'," 00151 "'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES'," 00152 "'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES'," 00153 "'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER'," 00154 "'HIGH_NOT_PRECEDENCE')")}, 00155 {NULL, 0} 00156 }, 00157 { 00158 {(char *) STRING_WITH_LEN("comment")}, 00159 {(char *) STRING_WITH_LEN("char(64)")}, 00160 {(char *) STRING_WITH_LEN("utf8")} 00161 } 00162 }; 00163 00164 00165 /* 00166 Compares 2 LEX strings regarding case. 00167 00168 SYNOPSIS 00169 sortcmp_lex_string() 00170 00171 s - first LEX_STRING 00172 t - second LEX_STRING 00173 cs - charset 00174 00175 RETURN VALUE 00176 -1 - s < t 00177 0 - s == t 00178 1 - s > t 00179 00180 Notes 00181 TIME.second_part is not considered during comparison 00182 */ 00183 00184 int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs) 00185 { 00186 return cs->coll->strnncollsp(cs, (uchar *) s.str,s.length, 00187 (uchar *) t.str,t.length, 0); 00188 } 00189 00190 00191 /* 00192 Reconstructs interval expression from interval type and expression 00193 value that is in form of a value of the smalles entity: 00194 For 00195 YEAR_MONTH - expression is in months 00196 DAY_MINUTE - expression is in minutes 00197 00198 SYNOPSIS 00199 Events::reconstruct_interval_expression() 00200 buf - preallocated String buffer to add the value to 00201 interval - the interval type (for instance YEAR_MONTH) 00202 expression - the value in the lowest entity 00203 00204 RETURNS 00205 0 - OK 00206 1 - Error 00207 */ 00208 00209 int 00210 Events::reconstruct_interval_expression(String *buf, 00211 interval_type interval, 00212 longlong expression) 00213 { 00214 ulonglong expr= expression; 00215 char tmp_buff[128], *end; 00216 bool close_quote= TRUE; 00217 int multipl= 0; 00218 char separator=':'; 00219 00220 switch (interval) { 00221 case INTERVAL_YEAR_MONTH: 00222 multipl= 12; 00223 separator= '-'; 00224 goto common_1_lev_code; 00225 case INTERVAL_DAY_HOUR: 00226 multipl= 24; 00227 separator= ' '; 00228 goto common_1_lev_code; 00229 case INTERVAL_HOUR_MINUTE: 00230 case INTERVAL_MINUTE_SECOND: 00231 multipl= 60; 00232 common_1_lev_code: 00233 buf->append('\''); 00234 end= longlong10_to_str(expression/multipl, tmp_buff, 10); 00235 buf->append(tmp_buff, (uint) (end- tmp_buff)); 00236 expr= expr - (expr/multipl)*multipl; 00237 break; 00238 case INTERVAL_DAY_MINUTE: 00239 { 00240 ulonglong tmp_expr= expr; 00241 00242 tmp_expr/=(24*60); 00243 buf->append('\''); 00244 end= longlong10_to_str(tmp_expr, tmp_buff, 10); 00245 buf->append(tmp_buff, (uint) (end- tmp_buff));// days 00246 buf->append(' '); 00247 00248 tmp_expr= expr - tmp_expr*(24*60);//minutes left 00249 end= longlong10_to_str(tmp_expr/60, tmp_buff, 10); 00250 buf->append(tmp_buff, (uint) (end- tmp_buff));// hours 00251 00252 expr= tmp_expr - (tmp_expr/60)*60; 00253 /* the code after the switch will finish */ 00254 } 00255 break; 00256 case INTERVAL_HOUR_SECOND: 00257 { 00258 ulonglong tmp_expr= expr; 00259 00260 buf->append('\''); 00261 end= longlong10_to_str(tmp_expr/3600, tmp_buff, 10); 00262 buf->append(tmp_buff, (uint) (end- tmp_buff));// hours 00263 buf->append(':'); 00264 00265 tmp_expr= tmp_expr - (tmp_expr/3600)*3600; 00266 end= longlong10_to_str(tmp_expr/60, tmp_buff, 10); 00267 buf->append(tmp_buff, (uint) (end- tmp_buff));// minutes 00268 00269 expr= tmp_expr - (tmp_expr/60)*60; 00270 /* the code after the switch will finish */ 00271 } 00272 break; 00273 case INTERVAL_DAY_SECOND: 00274 { 00275 ulonglong tmp_expr= expr; 00276 00277 tmp_expr/=(24*3600); 00278 buf->append('\''); 00279 end= longlong10_to_str(tmp_expr, tmp_buff, 10); 00280 buf->append(tmp_buff, (uint) (end- tmp_buff));// days 00281 buf->append(' '); 00282 00283 tmp_expr= expr - tmp_expr*(24*3600);//seconds left 00284 end= longlong10_to_str(tmp_expr/3600, tmp_buff, 10); 00285 buf->append(tmp_buff, (uint) (end- tmp_buff));// hours 00286 buf->append(':'); 00287 00288 tmp_expr= tmp_expr - (tmp_expr/3600)*3600; 00289 end= longlong10_to_str(tmp_expr/60, tmp_buff, 10); 00290 buf->append(tmp_buff, (uint) (end- tmp_buff));// minutes 00291 00292 expr= tmp_expr - (tmp_expr/60)*60; 00293 /* the code after the switch will finish */ 00294 } 00295 break; 00296 case INTERVAL_DAY_MICROSECOND: 00297 case INTERVAL_HOUR_MICROSECOND: 00298 case INTERVAL_MINUTE_MICROSECOND: 00299 case INTERVAL_SECOND_MICROSECOND: 00300 case INTERVAL_MICROSECOND: 00301 my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND"); 00302 return 1; 00303 break; 00304 case INTERVAL_QUARTER: 00305 expr/= 3; 00306 close_quote= FALSE; 00307 break; 00308 case INTERVAL_WEEK: 00309 expr/= 7; 00310 default: 00311 close_quote= FALSE; 00312 break; 00313 } 00314 if (close_quote) 00315 buf->append(separator); 00316 end= longlong10_to_str(expr, tmp_buff, 10); 00317 buf->append(tmp_buff, (uint) (end- tmp_buff)); 00318 if (close_quote) 00319 buf->append('\''); 00320 00321 return 0; 00322 } 00323 00324 00325 /* 00326 Open mysql.event table for read 00327 00328 SYNOPSIS 00329 Events::open_event_table() 00330 thd Thread context 00331 lock_type How to lock the table 00332 table We will store the open table here 00333 00334 RETURN VALUE 00335 1 Cannot lock table 00336 2 The table is corrupted - different number of fields 00337 0 OK 00338 */ 00339 00340 int 00341 Events::open_event_table(THD *thd, enum thr_lock_type lock_type, 00342 TABLE **table) 00343 { 00344 TABLE_LIST tables; 00345 DBUG_ENTER("open_events_table"); 00346 00347 bzero((char*) &tables, sizeof(tables)); 00348 tables.db= (char*) "mysql"; 00349 tables.table_name= tables.alias= (char*) "event"; 00350 tables.lock_type= lock_type; 00351 00352 if (simple_open_n_lock_tables(thd, &tables)) 00353 DBUG_RETURN(1); 00354 00355 if (table_check_intact(tables.table, Events::FIELD_COUNT, 00356 event_table_fields, 00357 &mysql_event_last_create_time, 00358 ER_CANNOT_LOAD_FROM_TABLE)) 00359 { 00360 close_thread_tables(thd); 00361 DBUG_RETURN(2); 00362 } 00363 *table= tables.table; 00364 tables.table->use_all_columns(); 00365 DBUG_RETURN(0); 00366 } 00367 00368 00369 /* 00370 Find row in open mysql.event table representing event 00371 00372 SYNOPSIS 00373 evex_db_find_event_aux() 00374 thd Thread context 00375 et event_timed object containing dbname & name 00376 table TABLE object for open mysql.event table. 00377 00378 RETURN VALUE 00379 0 - Routine found 00380 EVEX_KEY_NOT_FOUND - No routine with given name 00381 */ 00382 00383 inline int 00384 evex_db_find_event_aux(THD *thd, Event_timed *et, TABLE *table) 00385 { 00386 return evex_db_find_event_by_name(thd, et->dbname, et->name, table); 00387 } 00388 00389 00390 /* 00391 Find row in open mysql.event table representing event 00392 00393 SYNOPSIS 00394 evex_db_find_event_by_name() 00395 thd Thread context 00396 dbname Name of event's database 00397 rname Name of the event inside the db 00398 table TABLE object for open mysql.event table. 00399 00400 RETURN VALUE 00401 0 - Routine found 00402 EVEX_KEY_NOT_FOUND - No routine with given name 00403 */ 00404 00405 int 00406 evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname, 00407 const LEX_STRING ev_name, 00408 TABLE *table) 00409 { 00410 byte key[MAX_KEY_LENGTH]; 00411 DBUG_ENTER("evex_db_find_event_by_name"); 00412 DBUG_PRINT("enter", ("name: %.*s", ev_name.length, ev_name.str)); 00413 00414 /* 00415 Create key to find row. We have to use field->store() to be able to 00416 handle VARCHAR and CHAR fields. 00417 Assumption here is that the two first fields in the table are 00418 'db' and 'name' and the first key is the primary key over the 00419 same fields. 00420 */ 00421 if (dbname.length > table->field[Events::FIELD_DB]->field_length || 00422 ev_name.length > table->field[Events::FIELD_NAME]->field_length) 00423 00424 DBUG_RETURN(EVEX_KEY_NOT_FOUND); 00425 00426 table->field[Events::FIELD_DB]->store(dbname.str, dbname.length, 00427 &my_charset_bin); 00428 table->field[Events::FIELD_NAME]->store(ev_name.str, ev_name.length, 00429 &my_charset_bin); 00430 00431 key_copy(key, table->record[0], table->key_info, 00432 table->key_info->key_length); 00433 00434 if (table->file->index_read_idx(table->record[0], 0, key, 00435 table->key_info->key_length, 00436 HA_READ_KEY_EXACT)) 00437 { 00438 DBUG_PRINT("info", ("Row not found")); 00439 DBUG_RETURN(EVEX_KEY_NOT_FOUND); 00440 } 00441 00442 DBUG_PRINT("info", ("Row found!")); 00443 DBUG_RETURN(0); 00444 } 00445 00446 00447 /* 00448 Puts some data common to CREATE and ALTER EVENT into a row. 00449 00450 SYNOPSIS 00451 evex_fill_row() 00452 thd THD 00453 table the row to fill out 00454 et Event's data 00455 00456 RETURN VALUE 00457 0 - OK 00458 EVEX_GENERAL_ERROR - bad data 00459 EVEX_GET_FIELD_FAILED - field count does not match. table corrupted? 00460 00461 DESCRIPTION 00462 Used both when an event is created and when it is altered. 00463 */ 00464 00465 static int 00466 evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update) 00467 { 00468 CHARSET_INFO *scs= system_charset_info; 00469 enum Events::enum_table_field field_num; 00470 00471 DBUG_ENTER("evex_fill_row"); 00472 00473 DBUG_PRINT("info", ("dbname=[%s]", et->dbname.str)); 00474 DBUG_PRINT("info", ("name =[%s]", et->name.str)); 00475 DBUG_PRINT("info", ("body =[%s]", et->body.str)); 00476 00477 if (table->field[field_num= Events::FIELD_DEFINER]-> 00478 store(et->definer.str, et->definer.length, scs)) 00479 goto err_truncate; 00480 00481 if (table->field[field_num= Events::FIELD_DB]-> 00482 store(et->dbname.str, et->dbname.length, scs)) 00483 goto err_truncate; 00484 00485 if (table->field[field_num= Events::FIELD_NAME]-> 00486 store(et->name.str, et->name.length, scs)) 00487 goto err_truncate; 00488 00489 /* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()*/ 00490 table->field[Events::FIELD_ON_COMPLETION]-> 00491 store((longlong)et->on_completion, true); 00492 00493 table->field[Events::FIELD_STATUS]->store((longlong)et->status, true); 00494 00495 /* 00496 Change the SQL_MODE only if body was present in an ALTER EVENT and of course 00497 always during CREATE EVENT. 00498 */ 00499 if (et->body.str) 00500 { 00501 table->field[Events::FIELD_SQL_MODE]-> 00502 store((longlong)thd->variables.sql_mode, true); 00503 00504 if (table->field[field_num= Events::FIELD_BODY]-> 00505 store(et->body.str, et->body.length, scs)) 00506 goto err_truncate; 00507 } 00508 00509 if (et->expression) 00510 { 00511 table->field[Events::FIELD_INTERVAL_EXPR]->set_notnull(); 00512 table->field[Events::FIELD_INTERVAL_EXPR]-> 00513 store((longlong)et->expression, true); 00514 00515 table->field[Events::FIELD_TRANSIENT_INTERVAL]->set_notnull(); 00516 /* 00517 In the enum (C) intervals start from 0 but in mysql enum valid values start 00518 from 1. Thus +1 offset is needed! 00519 */ 00520 table->field[Events::FIELD_TRANSIENT_INTERVAL]-> 00521 store((longlong)et->interval+1, true); 00522 00523 table->field[Events::FIELD_EXECUTE_AT]->set_null(); 00524 00525 if (!et->starts_null) 00526 { 00527 table->field[Events::FIELD_STARTS]->set_notnull(); 00528 table->field[Events::FIELD_STARTS]-> 00529 store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME); 00530 } 00531 00532 if (!et->ends_null) 00533 { 00534 table->field[Events::FIELD_ENDS]->set_notnull(); 00535 table->field[Events::FIELD_ENDS]-> 00536 store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME); 00537 } 00538 } 00539 else if (et->execute_at.year) 00540 { 00541 table->field[Events::FIELD_INTERVAL_EXPR]->set_null(); 00542 table->field[Events::FIELD_TRANSIENT_INTERVAL]->set_null(); 00543 table->field[Events::FIELD_STARTS]->set_null(); 00544 table->field[Events::FIELD_ENDS]->set_null(); 00545 00546 table->field[Events::FIELD_EXECUTE_AT]->set_notnull(); 00547 table->field[Events::FIELD_EXECUTE_AT]-> 00548 store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME); 00549 } 00550 else 00551 { 00552 DBUG_ASSERT(is_update); 00553 /* 00554 it is normal to be here when the action is update 00555 this is an error if the action is create. something is borked 00556 */ 00557 } 00558 00559 ((Field_timestamp *)table->field[Events::FIELD_MODIFIED])->set_time(); 00560 00561 if (et->comment.str) 00562 { 00563 if (table->field[field_num= Events::FIELD_COMMENT]-> 00564 store(et->comment.str, et->comment.length, scs)) 00565 goto err_truncate; 00566 } 00567 00568 DBUG_RETURN(0); 00569 err_truncate: 00570 my_error(ER_EVENT_DATA_TOO_LONG, MYF(0), table->field[field_num]->field_name); 00571 DBUG_RETURN(EVEX_GENERAL_ERROR); 00572 } 00573 00574 00575 /* 00576 Creates an event in mysql.event 00577 00578 SYNOPSIS 00579 db_create_event() 00580 thd THD 00581 et Event_timed object containing information for the event 00582 create_if_not If an warning should be generated in case event exists 00583 rows_affected How many rows were affected 00584 00585 RETURN VALUE 00586 0 - OK 00587 EVEX_GENERAL_ERROR - Failure 00588 00589 DESCRIPTION 00590 Creates an event. Relies on evex_fill_row which is shared with 00591 db_update_event. The name of the event is inside "et". 00592 */ 00593 00594 int 00595 db_create_event(THD *thd, Event_timed *et, my_bool create_if_not, 00596 uint *rows_affected) 00597 { 00598 int ret= 0; 00599 CHARSET_INFO *scs= system_charset_info; 00600 TABLE *table; 00601 char old_db_buf[NAME_LEN+1]; 00602 LEX_STRING old_db= { old_db_buf, sizeof(old_db_buf) }; 00603 bool dbchanged= FALSE; 00604 DBUG_ENTER("db_create_event"); 00605 DBUG_PRINT("enter", ("name: %.*s", et->name.length, et->name.str)); 00606 00607 *rows_affected= 0; 00608 DBUG_PRINT("info", ("open mysql.event for update")); 00609 if (Events::open_event_table(thd, TL_WRITE, &table)) 00610 { 00611 my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0)); 00612 goto err; 00613 } 00614 00615 DBUG_PRINT("info", ("check existance of an event with the same name")); 00616 if (!evex_db_find_event_aux(thd, et, table)) 00617 { 00618 if (create_if_not) 00619 { 00620 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, 00621 ER_EVENT_ALREADY_EXISTS, ER(ER_EVENT_ALREADY_EXISTS), 00622 et->name.str); 00623 goto ok; 00624 } 00625 my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), et->name.str); 00626 goto err; 00627 } 00628 00629 DBUG_PRINT("info", ("non-existant, go forward")); 00630 if ((ret= sp_use_new_db(thd, et->dbname, &old_db, 0, &dbchanged))) 00631 { 00632 my_error(ER_BAD_DB_ERROR, MYF(0)); 00633 goto err; 00634 } 00635 00636 restore_record(table, s->default_values); // Get default values for fields 00637 00638 if (system_charset_info->cset->numchars(system_charset_info, et->dbname.str, 00639 et->dbname.str + et->dbname.length) 00640 > EVEX_DB_FIELD_LEN) 00641 { 00642 my_error(ER_TOO_LONG_IDENT, MYF(0), et->dbname.str); 00643 goto err; 00644 } 00645 if (system_charset_info->cset->numchars(system_charset_info, et->name.str, 00646 et->name.str + et->name.length) 00647 > EVEX_DB_FIELD_LEN) 00648 { 00649 my_error(ER_TOO_LONG_IDENT, MYF(0), et->name.str); 00650 goto err; 00651 } 00652 00653 if (et->body.length > table->field[Events::FIELD_BODY]->field_length) 00654 { 00655 my_error(ER_TOO_LONG_BODY, MYF(0), et->name.str); 00656 goto err; 00657 } 00658 00659 if (!(et->expression) && !(et->execute_at.year)) 00660 { 00661 DBUG_PRINT("error", ("neither expression nor execute_at are set!")); 00662 my_error(ER_EVENT_NEITHER_M_EXPR_NOR_M_AT, MYF(0)); 00663 goto err; 00664 } 00665 00666 ((Field_timestamp *)table->field[Events::FIELD_CREATED])->set_time(); 00667 00668 /* 00669 evex_fill_row() calls my_error() in case of error so no need to 00670 handle it here 00671 */ 00672 if ((ret= evex_fill_row(thd, table, et, false))) 00673 goto err; 00674 00675 if (table->file->ha_write_row(table->record[0])) 00676 { 00677 my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret); 00678 goto err; 00679 } 00680 00681 #ifdef USE_THIS_CODE_AS_TEMPLATE_WHEN_EVENT_REPLICATION_IS_AGREED 00682 if (mysql_bin_log.is_open()) 00683 { 00684 thd->clear_error(); 00685 /* Such a statement can always go directly to binlog, no trans cache */ 00686 thd->binlog_query(THD::MYSQL_QUERY_TYPE, thd->query, thd->query_length, 00687 FALSE, FALSE); 00688 } 00689 #endif 00690 00691 *rows_affected= 1; 00692 ok: 00693 if (dbchanged) 00694 (void) mysql_change_db(thd, old_db.str, 1); 00695 if (table) 00696 close_thread_tables(thd); 00697 DBUG_RETURN(EVEX_OK); 00698 00699 err: 00700 if (dbchanged) 00701 (void) mysql_change_db(thd, old_db.str, 1); 00702 if (table) 00703 close_thread_tables(thd); 00704 DBUG_RETURN(EVEX_GENERAL_ERROR); 00705 } 00706 00707 00708 /* 00709 Used to execute ALTER EVENT. Pendant to Events::update_event(). 00710 00711 SYNOPSIS 00712 db_update_event() 00713 thd THD 00714 sp_name the name of the event to alter 00715 et event's data 00716 00717 RETURN VALUE 00718 0 OK 00719 EVEX_GENERAL_ERROR Error occured (my_error() called) 00720 00721 NOTES 00722 sp_name is passed since this is the name of the event to 00723 alter in case of RENAME TO. 00724 */ 00725 00726 static int 00727 db_update_event(THD *thd, Event_timed *et, sp_name *new_name) 00728 { 00729 CHARSET_INFO *scs= system_charset_info; 00730 TABLE *table; 00731 int ret= EVEX_OPEN_TABLE_FAILED; 00732 DBUG_ENTER("db_update_event"); 00733 DBUG_PRINT("enter", ("dbname: %.*s", et->dbname.length, et->dbname.str)); 00734 DBUG_PRINT("enter", ("name: %.*s", et->name.length, et->name.str)); 00735 DBUG_PRINT("enter", ("user: %.*s", et->definer.length, et->definer.str)); 00736 if (new_name) 00737 DBUG_PRINT("enter", ("rename to: %.*s", new_name->m_name.length, 00738 new_name->m_name.str)); 00739 00740 if (Events::open_event_table(thd, TL_WRITE, &table)) 00741 { 00742 my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0)); 00743 goto err; 00744 } 00745 00746 /* first look whether we overwrite */ 00747 if (new_name) 00748 { 00749 if (!sortcmp_lex_string(et->name, new_name->m_name, scs) && 00750 !sortcmp_lex_string(et->dbname, new_name->m_db, scs)) 00751 { 00752 my_error(ER_EVENT_SAME_NAME, MYF(0), et->name.str); 00753 goto err; 00754 } 00755 00756 if (!evex_db_find_event_by_name(thd,new_name->m_db,new_name->m_name,table)) 00757 { 00758 my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->m_name.str); 00759 goto err; 00760 } 00761 } 00762 /* 00763 ...and then if there is such an event. Don't exchange the blocks 00764 because you will get error 120 from table handler because new_name will 00765 overwrite the key and SE will tell us that it cannot find the already found 00766 row (copied into record[1] later 00767 */ 00768 if (EVEX_KEY_NOT_FOUND == evex_db_find_event_aux(thd, et, table)) 00769 { 00770 my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), et->name.str); 00771 goto err; 00772 } 00773 00774 store_record(table,record[1]); 00775 00776 /* Don't update create on row update. */ 00777 table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; 00778 00779 /* 00780 evex_fill_row() calls my_error() in case of error so no need to 00781 handle it here 00782 */ 00783 if ((ret= evex_fill_row(thd, table, et, true))) 00784 goto err; 00785 00786 if (new_name) 00787 { 00788 table->field[Events::FIELD_DB]-> 00789 store(new_name->m_db.str, new_name->m_db.length, scs); 00790 table->field[Events::FIELD_NAME]-> 00791 store(new_name->m_name.str, new_name->m_name.length, scs); 00792 } 00793 00794 if ((ret= table->file->ha_update_row(table->record[1], table->record[0]))) 00795 { 00796 my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret); 00797 goto err; 00798 } 00799 00800 /* close mysql.event or we crash later when loading the event from disk */ 00801 close_thread_tables(thd); 00802 DBUG_RETURN(0); 00803 00804 err: 00805 if (table) 00806 close_thread_tables(thd); 00807 DBUG_RETURN(EVEX_GENERAL_ERROR); 00808 } 00809 00810 00811 /* 00812 Looks for a named event in mysql.event and in case of success returns 00813 an object will data loaded from the table. 00814 00815 SYNOPSIS 00816 db_find_event() 00817 thd THD 00818 name the name of the event to find 00819 ett event's data if event is found 00820 tbl TABLE object to use when not NULL 00821 00822 NOTES 00823 1) Use sp_name for look up, return in **ett if found 00824 2) tbl is not closed at exit 00825 00826 RETURN VALUE 00827 0 ok In this case *ett is set to the event 00828 # error *ett == 0 00829 */ 00830 00831 int 00832 db_find_event(THD *thd, sp_name *name, Event_timed **ett, TABLE *tbl, 00833 MEM_ROOT *root) 00834 { 00835 TABLE *table; 00836 int ret; 00837 Event_timed *et= NULL; 00838 DBUG_ENTER("db_find_event"); 00839 DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); 00840 00841 if (!root) 00842 root= &evex_mem_root; 00843 00844 if (tbl) 00845 table= tbl; 00846 else if (Events::open_event_table(thd, TL_READ, &table)) 00847 { 00848 my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0)); 00849 ret= EVEX_GENERAL_ERROR; 00850 goto done; 00851 } 00852 00853 if ((ret= evex_db_find_event_by_name(thd, name->m_db, name->m_name, table))) 00854 { 00855 my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name->m_name.str); 00856 goto done; 00857 } 00858 et= new Event_timed; 00859 00860 /* 00861 1)The table should not be closed beforehand. ::load_from_row() only loads 00862 and does not compile 00863 00864 2)::load_from_row() is silent on error therefore we emit error msg here 00865 */ 00866 if ((ret= et->load_from_row(root, table))) 00867 { 00868 my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0)); 00869 goto done; 00870 } 00871 00872 done: 00873 if (ret) 00874 { 00875 delete et; 00876 et= 0; 00877 } 00878 /* don't close the table if we haven't opened it ourselves */ 00879 if (!tbl && table) 00880 close_thread_tables(thd); 00881 *ett= et; 00882 DBUG_RETURN(ret); 00883 } 00884 00885 00886 /* 00887 The function exported to the world for creating of events. 00888 00889 SYNOPSIS 00890 Events::create_event() 00891 thd THD 00892 et event's data 00893 create_options Options specified when in the query. We are 00894 interested whether there is IF NOT EXISTS 00895 rows_affected How many rows were affected 00896 00897 RETURN VALUE 00898 0 OK 00899 !0 Error 00900 00901 NOTES 00902 - in case there is an event with the same name (db) and 00903 IF NOT EXISTS is specified, an warning is put into the W stack. 00904 */ 00905 00906 int 00907 Events::create_event(THD *thd, Event_timed *et, uint create_options, 00908 uint *rows_affected) 00909 { 00910 int ret; 00911 00912 DBUG_ENTER("Events::create_event"); 00913 DBUG_PRINT("enter", ("name: %*s options:%d", et->name.length, 00914 et->name.str, create_options)); 00915 00916 if (!(ret = db_create_event(thd, et, 00917 create_options & HA_LEX_CREATE_IF_NOT_EXISTS, 00918 rows_affected))) 00919 { 00920 Event_scheduler *scheduler= Event_scheduler::get_instance(); 00921 if (scheduler->initialized() && 00922 (ret= scheduler->create_event(thd, et, true))) 00923 my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret); 00924 } 00925 /* No need to close the table, it will be closed in sql_parse::do_command */ 00926 00927 DBUG_RETURN(ret); 00928 } 00929 00930 00931 /* 00932 The function exported to the world for alteration of events. 00933 00934 SYNOPSIS 00935 Events::update_event() 00936 thd THD 00937 et event's data 00938 new_name set in case of RENAME TO. 00939 00940 RETURN VALUE 00941 0 OK 00942 !0 Error 00943 00944 NOTES 00945 et contains data about dbname and event name. 00946 new_name is the new name of the event, if not null (this means 00947 that RENAME TO was specified in the query) 00948 */ 00949 00950 int 00951 Events::update_event(THD *thd, Event_timed *et, sp_name *new_name, 00952 uint *rows_affected) 00953 { 00954 int ret; 00955 00956 DBUG_ENTER("Events::update_event"); 00957 DBUG_PRINT("enter", ("name: %*s", et->name.length, et->name.str)); 00958 /* 00959 db_update_event() opens & closes the table to prevent 00960 crash later in the code when loading and compiling the new definition. 00961 Also on error conditions my_error() is called so no need to handle here 00962 */ 00963 if (!(ret= db_update_event(thd, et, new_name))) 00964 { 00965 Event_scheduler *scheduler= Event_scheduler::get_instance(); 00966 if (scheduler->initialized() && 00967 (ret= scheduler->update_event(thd, et, 00968 new_name? &new_name->m_db: NULL, 00969 new_name? &new_name->m_name: NULL))) 00970 my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret); 00971 } 00972 DBUG_RETURN(ret); 00973 } 00974 00975 00976 /* 00977 Drops an event 00978 00979 SYNOPSIS 00980 db_drop_event() 00981 thd THD 00982 et event's name 00983 drop_if_exists if set and the event not existing => warning onto the stack 00984 rows_affected affected number of rows is returned heres 00985 00986 RETURN VALUE 00987 0 OK 00988 !0 Error (my_error() called) 00989 */ 00990 00991 int db_drop_event(THD *thd, Event_timed *et, bool drop_if_exists, 00992 uint *rows_affected) 00993 { 00994 TABLE *table; 00995 Open_tables_state backup; 00996 int ret; 00997 00998 DBUG_ENTER("db_drop_event"); 00999 ret= EVEX_OPEN_TABLE_FAILED; 01000 01001 thd->reset_n_backup_open_tables_state(&backup); 01002 if (Events::open_event_table(thd, TL_WRITE, &table)) 01003 { 01004 my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0)); 01005 goto done; 01006 } 01007 01008 if (!(ret= evex_db_find_event_aux(thd, et, table))) 01009 { 01010 if ((ret= table->file->ha_delete_row(table->record[0]))) 01011 { 01012 my_error(ER_EVENT_CANNOT_DELETE, MYF(0)); 01013 goto done; 01014 } 01015 } 01016 else if (ret == EVEX_KEY_NOT_FOUND) 01017 { 01018 if (drop_if_exists) 01019 { 01020 push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, 01021 ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST), 01022 "Event", et->name.str); 01023 ret= 0; 01024 } else 01025 my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), et->name.str); 01026 goto done; 01027 } 01028 01029 01030 done: 01031 /* 01032 evex_drop_event() is used by Event_timed::drop therefore 01033 we have to close our thread tables. 01034 */ 01035 close_thread_tables(thd); 01036 thd->restore_backup_open_tables_state(&backup); 01037 DBUG_RETURN(ret); 01038 } 01039 01040 01041 /* 01042 Drops an event 01043 01044 SYNOPSIS 01045 Events::drop_event() 01046 thd THD 01047 et event's name 01048 drop_if_exists if set and the event not existing => warning onto the stack 01049 rows_affected affected number of rows is returned heres 01050 01051 RETURN VALUE 01052 0 OK 01053 !0 Error (reported) 01054 */ 01055 01056 int 01057 Events::drop_event(THD *thd, Event_timed *et, bool drop_if_exists, 01058 uint *rows_affected) 01059 { 01060 int ret; 01061 01062 DBUG_ENTER("Events::drop_event"); 01063 if (!(ret= db_drop_event(thd, et, drop_if_exists, rows_affected))) 01064 { 01065 Event_scheduler *scheduler= Event_scheduler::get_instance(); 01066 if (scheduler->initialized() && (ret= scheduler->drop_event(thd, et))) 01067 my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret); 01068 } 01069 01070 DBUG_RETURN(ret); 01071 } 01072 01073 01074 /* 01075 SHOW CREATE EVENT 01076 01077 SYNOPSIS 01078 Events::show_create_event() 01079 thd THD 01080 spn the name of the event (db, name) 01081 01082 RETURN VALUE 01083 0 OK 01084 1 Error during writing to the wire 01085 */ 01086 01087 int 01088 Events::show_create_event(THD *thd, sp_name *spn) 01089 { 01090 int ret; 01091 Event_timed *et= NULL; 01092 Open_tables_state backup; 01093 01094 DBUG_ENTER("evex_update_event"); 01095 DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str)); 01096 01097 thd->reset_n_backup_open_tables_state(&backup); 01098 ret= db_find_event(thd, spn, &et, NULL, thd->mem_root); 01099 thd->restore_backup_open_tables_state(&backup); 01100 01101 if (!ret) 01102 { 01103 Protocol *protocol= thd->protocol; 01104 char show_str_buf[768]; 01105 String show_str(show_str_buf, sizeof(show_str_buf), system_charset_info); 01106 List<Item> field_list; 01107 byte *sql_mode_str; 01108 ulong sql_mode_len=0; 01109 01110 show_str.length(0); 01111 show_str.set_charset(system_charset_info); 01112 01113 if (et->get_create_event(thd, &show_str)) 01114 goto err; 01115 01116 field_list.push_back(new Item_empty_string("Event", NAME_LEN)); 01117 01118 sql_mode_str= 01119 sys_var_thd_sql_mode::symbolic_mode_representation(thd, et->sql_mode, 01120 &sql_mode_len); 01121 01122 field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len)); 01123 01124 field_list.push_back(new Item_empty_string("Create Event", 01125 show_str.length())); 01126 if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS | 01127 Protocol::SEND_EOF)) 01128 goto err; 01129 01130 protocol->prepare_for_resend(); 01131 protocol->store(et->name.str, et->name.length, system_charset_info); 01132 01133 protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info); 01134 01135 protocol->store(show_str.c_ptr(), show_str.length(), system_charset_info); 01136 ret= protocol->write(); 01137 send_eof(thd); 01138 } 01139 delete et; 01140 DBUG_RETURN(ret); 01141 err: 01142 delete et; 01143 DBUG_RETURN(1); 01144 } 01145 01146 01147 /* 01148 Drops all events from a schema 01149 01150 SYNOPSIS 01151 Events::drop_schema_events() 01152 thd Thread 01153 db ASCIIZ schema name 01154 01155 RETURN VALUE 01156 0 OK 01157 !0 Error 01158 */ 01159 01160 int 01161 Events::drop_schema_events(THD *thd, char *db) 01162 { 01163 int ret= 0; 01164 LEX_STRING db_lex= {db, strlen(db)}; 01165 01166 DBUG_ENTER("evex_drop_db_events"); 01167 DBUG_PRINT("enter", ("dropping events from %s", db)); 01168 01169 Event_scheduler *scheduler= Event_scheduler::get_instance(); 01170 if (scheduler->initialized()) 01171 ret= scheduler->drop_schema_events(thd, &db_lex); 01172 else 01173 ret= db_drop_events_from_table(thd, &db_lex); 01174 01175 DBUG_RETURN(ret); 01176 } 01177 01178 01179 /* 01180 Drops all events in the selected database, from mysql.event. 01181 01182 SYNOPSIS 01183 evex_drop_db_events_from_table() 01184 thd Thread 01185 db Schema name 01186 01187 RETURN VALUE 01188 0 OK 01189 !0 Error from ha_delete_row 01190 */ 01191 01192 int 01193 db_drop_events_from_table(THD *thd, LEX_STRING *db) 01194 { 01195 int ret; 01196 TABLE *table; 01197 READ_RECORD read_record_info; 01198 DBUG_ENTER("db_drop_events_from_table"); 01199 DBUG_PRINT("info", ("dropping events from %s", db->str)); 01200 01201 if ((ret= Events::open_event_table(thd, TL_WRITE, &table))) 01202 { 01203 if (my_errno != ENOENT) 01204 sql_print_error("Table mysql.event is damaged. Got error %d on open", 01205 my_errno); 01206 DBUG_RETURN(ret); 01207 } 01208 /* only enabled events are in memory, so we go now and delete the rest */ 01209 init_read_record(&read_record_info, thd, table, NULL, 1, 0); 01210 while (!(read_record_info.read_record(&read_record_info)) && !ret) 01211 { 01212 char *et_db= get_field(thd->mem_root, 01213 table->field[Events::FIELD_DB]); 01214 01215 LEX_STRING et_db_lex= {et_db, strlen(et_db)}; 01216 DBUG_PRINT("info", ("Current event %s.%s", et_db, 01217 get_field(thd->mem_root, 01218 table->field[Events::FIELD_NAME]))); 01219 01220 if (!sortcmp_lex_string(et_db_lex, *db, system_charset_info)) 01221 { 01222 DBUG_PRINT("info", ("Dropping")); 01223 if ((ret= table->file->ha_delete_row(table->record[0]))) 01224 my_error(ER_EVENT_DROP_FAILED, MYF(0), 01225 get_field(thd->mem_root, 01226 table->field[Events::FIELD_NAME])); 01227 } 01228 } 01229 end_read_record(&read_record_info); 01230 thd->version--; /* Force close to free memory */ 01231 01232 close_thread_tables(thd); 01233 01234 DBUG_RETURN(ret); 01235 } 01236 01237 01238 01239 /* 01240 Inits the scheduler's structures. 01241 01242 SYNOPSIS 01243 Events::init() 01244 01245 NOTES 01246 This function is not synchronized. 01247 01248 RETURN VALUE 01249 0 OK 01250 1 Error 01251 */ 01252 01253 int 01254 Events::init() 01255 { 01256 int ret= 0; 01257 DBUG_ENTER("Events::init"); 01258 01259 /* it should be an assignment! */ 01260 if (opt_event_scheduler) 01261 { 01262 Event_scheduler *scheduler= Event_scheduler::get_instance(); 01263 DBUG_ASSERT(opt_event_scheduler == 1 || opt_event_scheduler == 2); 01264 DBUG_RETURN(scheduler->init() || 01265 (opt_event_scheduler == 1? scheduler->start(): 01266 scheduler->start_suspended())); 01267 } 01268 DBUG_RETURN(0); 01269 } 01270 01271 01272 /* 01273 Cleans up scheduler's resources. Called at server shutdown. 01274 01275 SYNOPSIS 01276 Events::shutdown() 01277 01278 NOTES 01279 This function is not synchronized. 01280 */ 01281 01282 void 01283 Events::shutdown() 01284 { 01285 DBUG_ENTER("Events::shutdown"); 01286 Event_scheduler *scheduler= Event_scheduler::get_instance(); 01287 if (scheduler->initialized()) 01288 { 01289 scheduler->stop(); 01290 scheduler->destroy(); 01291 } 01292 01293 DBUG_VOID_RETURN; 01294 } 01295 01296 01297 /* 01298 Proxy for Event_scheduler::dump_internal_status 01299 01300 SYNOPSIS 01301 Events::dump_internal_status() 01302 thd Thread 01303 01304 RETURN VALUE 01305 0 OK 01306 !0 Error 01307 */ 01308 01309 int 01310 Events::dump_internal_status(THD *thd) 01311 { 01312 return Event_scheduler::dump_internal_status(thd); 01313 } 01314 01315 01316 /* 01317 Inits Events mutexes 01318 01319 SYNOPSIS 01320 Events::init_mutexes() 01321 thd Thread 01322 */ 01323 01324 void 01325 Events::init_mutexes() 01326 { 01327 Event_scheduler::init_mutexes(); 01328 } 01329 01330 01331 /* 01332 Destroys Events mutexes 01333 01334 SYNOPSIS 01335 Events::destroy_mutexes() 01336 */ 01337 01338 void 01339 Events::destroy_mutexes() 01340 { 01341 Event_scheduler::destroy_mutexes(); 01342 }
1.4.7

