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 #define MYSQL_LEX 1 00018 #include "mysql_priv.h" 00019 #include "events_priv.h" 00020 #include "events.h" 00021 #include "event_timed.h" 00022 #include "sp_head.h" 00023 00024 00025 /* 00026 Constructor 00027 00028 SYNOPSIS 00029 Event_timed::Event_timed() 00030 */ 00031 00032 Event_timed::Event_timed():in_spawned_thread(0),locked_by_thread_id(0), 00033 running(0), thread_id(0), status_changed(false), 00034 last_executed_changed(false), expression(0), 00035 created(0), modified(0), 00036 on_completion(Event_timed::ON_COMPLETION_DROP), 00037 status(Event_timed::ENABLED), sphead(0), 00038 sql_mode(0), body_begin(0), dropped(false), 00039 free_sphead_on_delete(true), flags(0) 00040 00041 { 00042 pthread_mutex_init(&this->LOCK_running, MY_MUTEX_INIT_FAST); 00043 pthread_cond_init(&this->COND_finished, NULL); 00044 init(); 00045 } 00046 00047 00048 /* 00049 Destructor 00050 00051 SYNOPSIS 00052 Event_timed::~Event_timed() 00053 */ 00054 00055 Event_timed::~Event_timed() 00056 { 00057 deinit_mutexes(); 00058 00059 if (free_sphead_on_delete) 00060 free_sp(); 00061 } 00062 00063 00064 /* 00065 Destructor 00066 00067 SYNOPSIS 00068 Event_timed::~deinit_mutexes() 00069 */ 00070 00071 void 00072 Event_timed::deinit_mutexes() 00073 { 00074 pthread_mutex_destroy(&this->LOCK_running); 00075 pthread_cond_destroy(&this->COND_finished); 00076 } 00077 00078 00079 /* 00080 Checks whether the event is running 00081 00082 SYNOPSIS 00083 Event_timed::is_running() 00084 */ 00085 00086 bool 00087 Event_timed::is_running() 00088 { 00089 bool ret; 00090 00091 VOID(pthread_mutex_lock(&this->LOCK_running)); 00092 ret= running; 00093 VOID(pthread_mutex_unlock(&this->LOCK_running)); 00094 00095 return ret; 00096 } 00097 00098 00099 /* 00100 Init all member variables 00101 00102 SYNOPSIS 00103 Event_timed::init() 00104 */ 00105 00106 void 00107 Event_timed::init() 00108 { 00109 DBUG_ENTER("Event_timed::init"); 00110 00111 dbname.str= name.str= body.str= comment.str= 0; 00112 dbname.length= name.length= body.length= comment.length= 0; 00113 00114 set_zero_time(&starts, MYSQL_TIMESTAMP_DATETIME); 00115 set_zero_time(&ends, MYSQL_TIMESTAMP_DATETIME); 00116 set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME); 00117 set_zero_time(&last_executed, MYSQL_TIMESTAMP_DATETIME); 00118 starts_null= ends_null= execute_at_null= TRUE; 00119 00120 definer_user.str= definer_host.str= 0; 00121 definer_user.length= definer_host.length= 0; 00122 00123 sql_mode= 0; 00124 00125 DBUG_VOID_RETURN; 00126 } 00127 00128 00129 /* 00130 Set a name of the event 00131 00132 SYNOPSIS 00133 Event_timed::init_name() 00134 thd THD 00135 spn the name extracted in the parser 00136 */ 00137 00138 void 00139 Event_timed::init_name(THD *thd, sp_name *spn) 00140 { 00141 DBUG_ENTER("Event_timed::init_name"); 00142 /* During parsing, we must use thd->mem_root */ 00143 MEM_ROOT *root= thd->mem_root; 00144 00145 /* We have to copy strings to get them into the right memroot */ 00146 dbname.length= spn->m_db.length; 00147 dbname.str= strmake_root(root, spn->m_db.str, spn->m_db.length); 00148 name.length= spn->m_name.length; 00149 name.str= strmake_root(root, spn->m_name.str, spn->m_name.length); 00150 00151 if (spn->m_qname.length == 0) 00152 spn->init_qname(thd); 00153 00154 DBUG_PRINT("dbname", ("len=%d db=%s",dbname.length, dbname.str)); 00155 DBUG_PRINT("name", ("len=%d name=%s",name.length, name.str)); 00156 00157 DBUG_VOID_RETURN; 00158 } 00159 00160 00161 /* 00162 Set body of the event - what should be executed. 00163 00164 SYNOPSIS 00165 Event_timed::init_body() 00166 thd THD 00167 00168 NOTE 00169 The body is extracted by copying all data between the 00170 start of the body set by another method and the current pointer in Lex. 00171 00172 Some questionable removal of characters is done in here, and that part 00173 should be refactored when the parser is smarter. 00174 */ 00175 00176 void 00177 Event_timed::init_body(THD *thd) 00178 { 00179 DBUG_ENTER("Event_timed::init_body"); 00180 DBUG_PRINT("info", ("body=[%s] body_begin=0x%ld end=0x%ld", body_begin, 00181 body_begin, thd->lex->ptr)); 00182 00183 body.length= thd->lex->ptr - body_begin; 00184 const uchar *body_end= body_begin + body.length - 1; 00185 00186 /* Trim nuls or close-comments ('*'+'/') or spaces at the end */ 00187 while (body_begin < body_end) 00188 { 00189 00190 if ((*body_end == '\0') || 00191 (my_isspace(thd->variables.character_set_client, *body_end))) 00192 { /* consume NULs and meaningless whitespace */ 00193 --body.length; 00194 --body_end; 00195 continue; 00196 } 00197 00198 /* 00199 consume closing comments 00200 00201 This is arguably wrong, but it's the best we have until the parser is 00202 changed to be smarter. FIXME PARSER 00203 00204 See also the sp_head code, where something like this is done also. 00205 00206 One idea is to keep in the lexer structure the count of the number of 00207 open-comments we've entered, and scan left-to-right looking for a 00208 closing comment IFF the count is greater than zero. 00209 00210 Another idea is to remove the closing comment-characters wholly in the 00211 parser, since that's where it "removes" the opening characters. 00212 */ 00213 if ((*(body_end - 1) == '*') && (*body_end == '/')) 00214 { 00215 DBUG_PRINT("info", ("consumend one '*" "/' comment in the query '%s'", 00216 body_begin)); 00217 body.length-= 2; 00218 body_end-= 2; 00219 continue; 00220 } 00221 00222 break; /* none were found, so we have excised all we can. */ 00223 } 00224 00225 /* the first is always whitespace which I cannot skip in the parser */ 00226 while (my_isspace(thd->variables.character_set_client, *body_begin)) 00227 { 00228 ++body_begin; 00229 --body.length; 00230 } 00231 body.str= strmake_root(thd->mem_root, (char *)body_begin, body.length); 00232 00233 DBUG_VOID_RETURN; 00234 } 00235 00236 00237 /* 00238 Set time for execution for one time events. 00239 00240 SYNOPSIS 00241 Event_timed::init_execute_at() 00242 expr when (datetime) 00243 00244 RETURN VALUE 00245 0 OK 00246 EVEX_PARSE_ERROR fix_fields failed 00247 EVEX_BAD_PARAMS datetime is in the past 00248 ER_WRONG_VALUE wrong value for execute at 00249 */ 00250 00251 int 00252 Event_timed::init_execute_at(THD *thd, Item *expr) 00253 { 00254 my_bool not_used; 00255 TIME ltime; 00256 my_time_t t; 00257 00258 TIME time_tmp; 00259 DBUG_ENTER("Event_timed::init_execute_at"); 00260 00261 if (expr->fix_fields(thd, &expr)) 00262 DBUG_RETURN(EVEX_PARSE_ERROR); 00263 00264 /* no starts and/or ends in case of execute_at */ 00265 DBUG_PRINT("info", ("starts_null && ends_null should be 1 is %d", 00266 (starts_null && ends_null))); 00267 DBUG_ASSERT(starts_null && ends_null); 00268 00269 /* let's check whether time is in the past */ 00270 thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, 00271 (my_time_t) thd->query_start()); 00272 00273 if ((not_used= expr->get_date(<ime, TIME_NO_ZERO_DATE))) 00274 DBUG_RETURN(ER_WRONG_VALUE); 00275 00276 if (TIME_to_ulonglong_datetime(<ime) < 00277 TIME_to_ulonglong_datetime(&time_tmp)) 00278 DBUG_RETURN(EVEX_BAD_PARAMS); 00279 00280 /* 00281 This may result in a 1970-01-01 date if ltime is > 2037-xx-xx. 00282 CONVERT_TZ has similar problem. 00283 mysql_priv.h currently lists 00284 #define TIMESTAMP_MAX_YEAR 2038 (see TIME_to_timestamp()) 00285 */ 00286 my_tz_UTC->gmt_sec_to_TIME(<ime,t=TIME_to_timestamp(thd,<ime,¬_used)); 00287 if (!t) 00288 { 00289 DBUG_PRINT("error", ("Execute AT after year 2037")); 00290 DBUG_RETURN(ER_WRONG_VALUE); 00291 } 00292 00293 execute_at_null= FALSE; 00294 execute_at= ltime; 00295 DBUG_RETURN(0); 00296 } 00297 00298 00299 /* 00300 Set time for execution for transient events. 00301 00302 SYNOPSIS 00303 Event_timed::init_interval() 00304 expr how much? 00305 new_interval what is the interval 00306 00307 RETURN VALUE 00308 0 OK 00309 EVEX_PARSE_ERROR fix_fields failed 00310 EVEX_BAD_PARAMS Interval is not positive 00311 EVEX_MICROSECOND_UNSUP Microseconds are not supported. 00312 */ 00313 00314 int 00315 Event_timed::init_interval(THD *thd, Item *expr, interval_type new_interval) 00316 { 00317 String value; 00318 INTERVAL interval_tmp; 00319 00320 DBUG_ENTER("Event_timed::init_interval"); 00321 00322 if (expr->fix_fields(thd, &expr)) 00323 DBUG_RETURN(EVEX_PARSE_ERROR); 00324 00325 value.alloc(MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN); 00326 if (get_interval_value(expr, new_interval, &value, &interval_tmp)) 00327 DBUG_RETURN(EVEX_PARSE_ERROR); 00328 00329 expression= 0; 00330 00331 switch (new_interval) { 00332 case INTERVAL_YEAR: 00333 expression= interval_tmp.year; 00334 break; 00335 case INTERVAL_QUARTER: 00336 case INTERVAL_MONTH: 00337 expression= interval_tmp.month; 00338 break; 00339 case INTERVAL_WEEK: 00340 case INTERVAL_DAY: 00341 expression= interval_tmp.day; 00342 break; 00343 case INTERVAL_HOUR: 00344 expression= interval_tmp.hour; 00345 break; 00346 case INTERVAL_MINUTE: 00347 expression= interval_tmp.minute; 00348 break; 00349 case INTERVAL_SECOND: 00350 expression= interval_tmp.second; 00351 break; 00352 case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM 00353 expression= interval_tmp.year* 12 + interval_tmp.month; 00354 break; 00355 case INTERVAL_DAY_HOUR: 00356 expression= interval_tmp.day* 24 + interval_tmp.hour; 00357 break; 00358 case INTERVAL_DAY_MINUTE: 00359 expression= (interval_tmp.day* 24 + interval_tmp.hour) * 60 + 00360 interval_tmp.minute; 00361 break; 00362 case INTERVAL_HOUR_SECOND: /* day is anyway 0 */ 00363 case INTERVAL_DAY_SECOND: 00364 /* DAY_SECOND having problems because of leap seconds? */ 00365 expression= ((interval_tmp.day* 24 + interval_tmp.hour) * 60 + 00366 interval_tmp.minute)*60 00367 + interval_tmp.second; 00368 break; 00369 case INTERVAL_MINUTE_MICROSECOND: /* day and hour are 0 */ 00370 case INTERVAL_HOUR_MICROSECOND: /* day is anyway 0 */ 00371 case INTERVAL_DAY_MICROSECOND: 00372 DBUG_RETURN(EVEX_MICROSECOND_UNSUP); 00373 expression= ((((interval_tmp.day*24) + interval_tmp.hour)*60+ 00374 interval_tmp.minute)*60 + 00375 interval_tmp.second) * 1000000L + interval_tmp.second_part; 00376 break; 00377 case INTERVAL_HOUR_MINUTE: 00378 expression= interval_tmp.hour * 60 + interval_tmp.minute; 00379 break; 00380 case INTERVAL_MINUTE_SECOND: 00381 expression= interval_tmp.minute * 60 + interval_tmp.second; 00382 break; 00383 case INTERVAL_SECOND_MICROSECOND: 00384 DBUG_RETURN(EVEX_MICROSECOND_UNSUP); 00385 expression= interval_tmp.second * 1000000L + interval_tmp.second_part; 00386 break; 00387 case INTERVAL_MICROSECOND: 00388 DBUG_RETURN(EVEX_MICROSECOND_UNSUP); 00389 case INTERVAL_LAST: 00390 DBUG_ASSERT(0); 00391 } 00392 if (interval_tmp.neg || expression > EVEX_MAX_INTERVAL_VALUE) 00393 DBUG_RETURN(EVEX_BAD_PARAMS); 00394 00395 interval= new_interval; 00396 DBUG_RETURN(0); 00397 } 00398 00399 00400 /* 00401 Set activation time. 00402 00403 SYNOPSIS 00404 Event_timed::init_starts() 00405 expr how much? 00406 interval what is the interval 00407 00408 NOTES 00409 Note that activation time is not execution time. 00410 EVERY 5 MINUTE STARTS "2004-12-12 10:00:00" means that 00411 the event will be executed every 5 minutes but this will 00412 start at the date shown above. Expressions are possible : 00413 DATE_ADD(NOW(), INTERVAL 1 DAY) -- start tommorow at 00414 same time. 00415 00416 RETURN VALUE 00417 0 OK 00418 EVEX_PARSE_ERROR fix_fields failed 00419 EVEX_BAD_PARAMS starts before now 00420 */ 00421 00422 int 00423 Event_timed::init_starts(THD *thd, Item *new_starts) 00424 { 00425 my_bool not_used; 00426 TIME ltime, time_tmp; 00427 my_time_t t; 00428 00429 DBUG_ENTER("Event_timed::init_starts"); 00430 00431 if (new_starts->fix_fields(thd, &new_starts)) 00432 DBUG_RETURN(EVEX_PARSE_ERROR); 00433 00434 if ((not_used= new_starts->get_date(<ime, TIME_NO_ZERO_DATE))) 00435 DBUG_RETURN(EVEX_BAD_PARAMS); 00436 00437 /* Let's check whether time is in the past */ 00438 thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp, 00439 (my_time_t) thd->query_start()); 00440 00441 DBUG_PRINT("info",("now =%lld", TIME_to_ulonglong_datetime(&time_tmp))); 00442 DBUG_PRINT("info",("starts=%lld", TIME_to_ulonglong_datetime(<ime))); 00443 if (TIME_to_ulonglong_datetime(<ime) < 00444 TIME_to_ulonglong_datetime(&time_tmp)) 00445 DBUG_RETURN(EVEX_BAD_PARAMS); 00446 00447 /* 00448 This may result in a 1970-01-01 date if ltime is > 2037-xx-xx. 00449 CONVERT_TZ has similar problem. 00450 mysql_priv.h currently lists 00451 #define TIMESTAMP_MAX_YEAR 2038 (see TIME_to_timestamp()) 00452 */ 00453 my_tz_UTC->gmt_sec_to_TIME(<ime,t=TIME_to_timestamp(thd, <ime, ¬_used)); 00454 if (!t) 00455 { 00456 DBUG_PRINT("error", ("STARTS after year 2037")); 00457 DBUG_RETURN(EVEX_BAD_PARAMS); 00458 } 00459 00460 starts= ltime; 00461 starts_null= FALSE; 00462 DBUG_RETURN(0); 00463 } 00464 00465 00466 /* 00467 Set deactivation time. 00468 00469 SYNOPSIS 00470 Event_timed::init_ends() 00471 thd THD 00472 new_ends when? 00473 00474 NOTES 00475 Note that activation time is not execution time. 00476 EVERY 5 MINUTE ENDS "2004-12-12 10:00:00" means that 00477 the event will be executed every 5 minutes but this will 00478 end at the date shown above. Expressions are possible : 00479 DATE_ADD(NOW(), INTERVAL 1 DAY) -- end tommorow at 00480 same time. 00481 00482 RETURN VALUE 00483 0 OK 00484 EVEX_PARSE_ERROR fix_fields failed 00485 ER_WRONG_VALUE starts distant date (after year 2037) 00486 EVEX_BAD_PARAMS ENDS before STARTS 00487 */ 00488 00489 int 00490 Event_timed::init_ends(THD *thd, Item *new_ends) 00491 { 00492 TIME ltime, ltime_now; 00493 my_bool not_used; 00494 my_time_t t; 00495 00496 DBUG_ENTER("Event_timed::init_ends"); 00497 00498 if (new_ends->fix_fields(thd, &new_ends)) 00499 DBUG_RETURN(EVEX_PARSE_ERROR); 00500 00501 DBUG_PRINT("info", ("convert to TIME")); 00502 if ((not_used= new_ends->get_date(<ime, TIME_NO_ZERO_DATE))) 00503 DBUG_RETURN(EVEX_BAD_PARAMS); 00504 00505 /* 00506 This may result in a 1970-01-01 date if ltime is > 2037-xx-xx. 00507 CONVERT_TZ has similar problem. 00508 mysql_priv.h currently lists 00509 #define TIMESTAMP_MAX_YEAR 2038 (see TIME_to_timestamp()) 00510 */ 00511 DBUG_PRINT("info", ("get the UTC time")); 00512 my_tz_UTC->gmt_sec_to_TIME(<ime,t=TIME_to_timestamp(thd, <ime, ¬_used)); 00513 if (!t) 00514 { 00515 DBUG_PRINT("error", ("ENDS after year 2037")); 00516 DBUG_RETURN(EVEX_BAD_PARAMS); 00517 } 00518 00519 /* Check whether ends is after starts */ 00520 DBUG_PRINT("info", ("ENDS after STARTS?")); 00521 if (!starts_null && my_time_compare(&starts, <ime) != -1) 00522 DBUG_RETURN(EVEX_BAD_PARAMS); 00523 00524 /* 00525 The parser forces starts to be provided but one day STARTS could be 00526 set before NOW() and in this case the following check should be done. 00527 Check whether ENDS is not in the past. 00528 */ 00529 DBUG_PRINT("info", ("ENDS after NOW?")); 00530 my_tz_UTC->gmt_sec_to_TIME(<ime_now, thd->query_start()); 00531 if (my_time_compare(<ime_now, <ime) == 1) 00532 DBUG_RETURN(EVEX_BAD_PARAMS); 00533 00534 ends= ltime; 00535 ends_null= FALSE; 00536 DBUG_RETURN(0); 00537 } 00538 00539 00540 /* 00541 Sets comment. 00542 00543 SYNOPSIS 00544 Event_timed::init_comment() 00545 thd THD - used for memory allocation 00546 comment the string. 00547 */ 00548 00549 void 00550 Event_timed::init_comment(THD *thd, LEX_STRING *set_comment) 00551 { 00552 DBUG_ENTER("Event_timed::init_comment"); 00553 00554 comment.str= strmake_root(thd->mem_root, set_comment->str, 00555 comment.length= set_comment->length); 00556 00557 DBUG_VOID_RETURN; 00558 } 00559 00560 00561 /* 00562 Inits definer (definer_user and definer_host) during parsing. 00563 00564 SYNOPSIS 00565 Event_timed::init_definer() 00566 00567 RETURN VALUE 00568 0 OK 00569 */ 00570 00571 int 00572 Event_timed::init_definer(THD *thd) 00573 { 00574 DBUG_ENTER("Event_timed::init_definer"); 00575 00576 DBUG_PRINT("info",("init definer_user thd->mem_root=0x%lx " 00577 "thd->sec_ctx->priv_user=0x%lx", thd->mem_root, 00578 thd->security_ctx->priv_user)); 00579 definer_user.str= strdup_root(thd->mem_root, thd->security_ctx->priv_user); 00580 definer_user.length= strlen(thd->security_ctx->priv_user); 00581 00582 DBUG_PRINT("info",("init definer_host thd->s_c->priv_host=0x%lx", 00583 thd->security_ctx->priv_host)); 00584 definer_host.str= strdup_root(thd->mem_root, thd->security_ctx->priv_host); 00585 definer_host.length= strlen(thd->security_ctx->priv_host); 00586 00587 DBUG_PRINT("info",("init definer as whole")); 00588 definer.length= definer_user.length + definer_host.length + 1; 00589 definer.str= alloc_root(thd->mem_root, definer.length + 1); 00590 00591 DBUG_PRINT("info",("copy the user")); 00592 memcpy(definer.str, definer_user.str, definer_user.length); 00593 definer.str[definer_user.length]= '@'; 00594 00595 DBUG_PRINT("info",("copy the host")); 00596 memcpy(definer.str + definer_user.length + 1, definer_host.str, 00597 definer_host.length); 00598 definer.str[definer.length]= '\0'; 00599 DBUG_PRINT("info",("definer initted")); 00600 00601 DBUG_RETURN(0); 00602 } 00603 00604 00605 /* 00606 Loads an event from a row from mysql.event 00607 00608 SYNOPSIS 00609 Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table) 00610 00611 RETURN VALUE 00612 0 OK 00613 EVEX_GET_FIELD_FAILED Error 00614 00615 NOTES 00616 This method is silent on errors and should behave like that. Callers 00617 should handle throwing of error messages. The reason is that the class 00618 should not know about how to deal with communication. 00619 */ 00620 00621 int 00622 Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table) 00623 { 00624 char *ptr; 00625 Event_timed *et; 00626 uint len; 00627 bool res1, res2; 00628 00629 DBUG_ENTER("Event_timed::load_from_row"); 00630 00631 if (!table) 00632 goto error; 00633 00634 et= this; 00635 00636 if (table->s->fields != Events::FIELD_COUNT) 00637 goto error; 00638 00639 if ((et->dbname.str= get_field(mem_root, 00640 table->field[Events::FIELD_DB])) == NULL) 00641 goto error; 00642 00643 et->dbname.length= strlen(et->dbname.str); 00644 00645 if ((et->name.str= get_field(mem_root, 00646 table->field[Events::FIELD_NAME])) == NULL) 00647 goto error; 00648 00649 et->name.length= strlen(et->name.str); 00650 00651 if ((et->body.str= get_field(mem_root, 00652 table->field[Events::FIELD_BODY])) == NULL) 00653 goto error; 00654 00655 et->body.length= strlen(et->body.str); 00656 00657 if ((et->definer.str= get_field(mem_root, 00658 table->field[Events::FIELD_DEFINER])) == NullS) 00659 goto error; 00660 et->definer.length= strlen(et->definer.str); 00661 00662 ptr= strchr(et->definer.str, '@'); 00663 00664 if (! ptr) 00665 ptr= et->definer.str; 00666 00667 len= ptr - et->definer.str; 00668 00669 et->definer_user.str= strmake_root(mem_root, et->definer.str, len); 00670 et->definer_user.length= len; 00671 len= et->definer.length - len - 1; //1 is because of @ 00672 et->definer_host.str= strmake_root(mem_root, ptr + 1, len);/* 1:because of @*/ 00673 et->definer_host.length= len; 00674 00675 et->starts_null= table->field[Events::FIELD_STARTS]->is_null(); 00676 res1= table->field[Events::FIELD_STARTS]-> 00677 get_date(&et->starts,TIME_NO_ZERO_DATE); 00678 00679 et->ends_null= table->field[Events::FIELD_ENDS]->is_null(); 00680 res2= table->field[Events::FIELD_ENDS]->get_date(&et->ends, TIME_NO_ZERO_DATE); 00681 00682 if (!table->field[Events::FIELD_INTERVAL_EXPR]->is_null()) 00683 et->expression= table->field[Events::FIELD_INTERVAL_EXPR]->val_int(); 00684 else 00685 et->expression= 0; 00686 /* 00687 If res1 and res2 are true then both fields are empty. 00688 Hence if Events::FIELD_EXECUTE_AT is empty there is an error. 00689 */ 00690 et->execute_at_null= 00691 table->field[Events::FIELD_EXECUTE_AT]->is_null(); 00692 DBUG_ASSERT(!(et->starts_null && et->ends_null && !et->expression && 00693 et->execute_at_null)); 00694 if (!et->expression && 00695 table->field[Events::FIELD_EXECUTE_AT]-> get_date(&et->execute_at, 00696 TIME_NO_ZERO_DATE)) 00697 goto error; 00698 00699 /* 00700 In DB the values start from 1 but enum interval_type starts 00701 from 0 00702 */ 00703 if (!table->field[Events::FIELD_TRANSIENT_INTERVAL]->is_null()) 00704 et->interval= (interval_type) ((ulonglong) 00705 table->field[Events::FIELD_TRANSIENT_INTERVAL]->val_int() - 1); 00706 else 00707 et->interval= (interval_type) 0; 00708 00709 et->created= table->field[Events::FIELD_CREATED]->val_int(); 00710 et->modified= table->field[Events::FIELD_MODIFIED]->val_int(); 00711 00712 table->field[Events::FIELD_LAST_EXECUTED]-> 00713 get_date(&et->last_executed, TIME_NO_ZERO_DATE); 00714 00715 last_executed_changed= false; 00716 00717 /* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */ 00718 if ((ptr= get_field(mem_root, table->field[Events::FIELD_STATUS])) == NullS) 00719 goto error; 00720 00721 DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", et->name.str, ptr)); 00722 et->status= (ptr[0]=='E'? Event_timed::ENABLED:Event_timed::DISABLED); 00723 00724 /* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */ 00725 if ((ptr= get_field(mem_root, 00726 table->field[Events::FIELD_ON_COMPLETION])) == NullS) 00727 goto error; 00728 00729 et->on_completion= (ptr[0]=='D'? Event_timed::ON_COMPLETION_DROP: 00730 Event_timed::ON_COMPLETION_PRESERVE); 00731 00732 et->comment.str= get_field(mem_root, table->field[Events::FIELD_COMMENT]); 00733 if (et->comment.str != NullS) 00734 et->comment.length= strlen(et->comment.str); 00735 else 00736 et->comment.length= 0; 00737 00738 00739 et->sql_mode= (ulong) table->field[Events::FIELD_SQL_MODE]->val_int(); 00740 00741 DBUG_RETURN(0); 00742 error: 00743 DBUG_RETURN(EVEX_GET_FIELD_FAILED); 00744 } 00745 00746 00747 /* 00748 Computes the sum of a timestamp plus interval. Presumed is that at least one 00749 previous execution has occured. 00750 00751 SYNOPSIS 00752 get_next_time(TIME *start, int interval_value, interval_type interval) 00753 next the sum 00754 start add interval_value to this time 00755 time_now current time 00756 i_value quantity of time type interval to add 00757 i_type type of interval to add (SECOND, MINUTE, HOUR, WEEK ...) 00758 00759 RETURN VALUE 00760 0 OK 00761 1 Error 00762 00763 NOTES 00764 1) If the interval is conversible to SECOND, like MINUTE, HOUR, DAY, WEEK. 00765 Then we use TIMEDIFF()'s implementation as underlying and number of 00766 seconds as resolution for computation. 00767 2) In all other cases - MONTH, QUARTER, YEAR we use MONTH as resolution 00768 and PERIOD_DIFF()'s implementation 00769 3) We get the difference between time_now and `start`, then divide it 00770 by the months, respectively seconds and round up. Then we multiply 00771 monts/seconds by the rounded value and add it to `start` -> we get 00772 the next execution time. 00773 */ 00774 00775 static 00776 bool get_next_time(TIME *next, TIME *start, TIME *time_now, TIME *last_exec, 00777 int i_value, interval_type i_type) 00778 { 00779 bool ret; 00780 INTERVAL interval; 00781 TIME tmp; 00782 longlong months=0, seconds=0; 00783 DBUG_ENTER("get_next_time"); 00784 DBUG_PRINT("enter", ("start=%llu now=%llu", TIME_to_ulonglong_datetime(start), 00785 TIME_to_ulonglong_datetime(time_now))); 00786 00787 bzero(&interval, sizeof(interval)); 00788 00789 switch (i_type) { 00790 case INTERVAL_YEAR: 00791 months= i_value*12; 00792 break; 00793 case INTERVAL_QUARTER: 00794 /* Has already been converted to months */ 00795 case INTERVAL_YEAR_MONTH: 00796 case INTERVAL_MONTH: 00797 months= i_value; 00798 break; 00799 case INTERVAL_WEEK: 00800 /* WEEK has already been converted to days */ 00801 case INTERVAL_DAY: 00802 seconds= i_value*24*3600; 00803 break; 00804 case INTERVAL_DAY_HOUR: 00805 case INTERVAL_HOUR: 00806 seconds= i_value*3600; 00807 break; 00808 case INTERVAL_DAY_MINUTE: 00809 case INTERVAL_HOUR_MINUTE: 00810 case INTERVAL_MINUTE: 00811 seconds= i_value*60; 00812 break; 00813 case INTERVAL_DAY_SECOND: 00814 case INTERVAL_HOUR_SECOND: 00815 case INTERVAL_MINUTE_SECOND: 00816 case INTERVAL_SECOND: 00817 seconds= i_value; 00818 break; 00819 case INTERVAL_DAY_MICROSECOND: 00820 case INTERVAL_HOUR_MICROSECOND: 00821 case INTERVAL_MINUTE_MICROSECOND: 00822 case INTERVAL_SECOND_MICROSECOND: 00823 case INTERVAL_MICROSECOND: 00824 /* 00825 We should return an error here so SHOW EVENTS/ SELECT FROM I_S.EVENTS 00826 would give an error then. 00827 */ 00828 DBUG_RETURN(1); 00829 break; 00830 case INTERVAL_LAST: 00831 DBUG_ASSERT(0); 00832 } 00833 DBUG_PRINT("info", ("seconds=%ld months=%ld", seconds, months)); 00834 if (seconds) 00835 { 00836 longlong seconds_diff; 00837 long microsec_diff; 00838 00839 if (calc_time_diff(time_now, start, 1, &seconds_diff, µsec_diff)) 00840 { 00841 DBUG_PRINT("error", ("negative difference")); 00842 DBUG_ASSERT(0); 00843 } 00844 uint multiplier= seconds_diff / seconds; 00845 /* 00846 Increase the multiplier is the modulus is not zero to make round up. 00847 Or if time_now==start then we should not execute the same 00848 event two times for the same time 00849 get the next exec if the modulus is not 00850 */ 00851 DBUG_PRINT("info", ("multiplier=%d", multiplier)); 00852 if (seconds_diff % seconds || (!seconds_diff && last_exec->year) || 00853 TIME_to_ulonglong_datetime(time_now) == 00854 TIME_to_ulonglong_datetime(last_exec)) 00855 ++multiplier; 00856 interval.second= seconds * multiplier; 00857 DBUG_PRINT("info", ("multiplier=%u interval.second=%u", multiplier, 00858 interval.second)); 00859 tmp= *start; 00860 if (!(ret= date_add_interval(&tmp, INTERVAL_SECOND, interval))) 00861 *next= tmp; 00862 } 00863 else 00864 { 00865 /* PRESUMED is that at least one execution took already place */ 00866 int diff_months= (time_now->year - start->year)*12 + 00867 (time_now->month - start->month); 00868 /* 00869 Note: If diff_months is 0 that means we are in the same month as the 00870 last execution which is also the first execution. 00871 */ 00872 /* 00873 First we try with the smaller if not then + 1, because if we try with 00874 directly with +1 we will be after the current date but it could be that 00875 we will be 1 month ahead, so 2 steps are necessary. 00876 */ 00877 interval.month= (diff_months / months)*months; 00878 /* 00879 Check if the same month as last_exec (always set - prerequisite) 00880 An event happens at most once per month so there is no way to schedule 00881 it two times for the current month. This saves us from two calls to 00882 date_add_interval() if the event was just executed. But if the scheduler 00883 is started and there was at least 1 scheduled date skipped this one does 00884 not help and two calls to date_add_interval() will be done, which is a 00885 bit more expensive but compared to the rareness of the case is neglectable. 00886 */ 00887 if (time_now->year==last_exec->year && time_now->month==last_exec->month) 00888 interval.month+= months; 00889 00890 tmp= *start; 00891 if ((ret= date_add_interval(&tmp, INTERVAL_MONTH, interval))) 00892 goto done; 00893 00894 /* If `tmp` is still before time_now just add one more time the interval */ 00895 if (my_time_compare(&tmp, time_now) == -1) 00896 { 00897 interval.month+= months; 00898 tmp= *start; 00899 if ((ret= date_add_interval(&tmp, INTERVAL_MONTH, interval))) 00900 goto done; 00901 } 00902 *next= tmp; 00903 /* assert on that the next is after now */ 00904 DBUG_ASSERT(1==my_time_compare(next, time_now)); 00905 } 00906 00907 done: 00908 DBUG_PRINT("info", ("next=%llu", TIME_to_ulonglong_datetime(next))); 00909 DBUG_RETURN(ret); 00910 } 00911 00912 00913 /* 00914 Computes next execution time. 00915 00916 SYNOPSIS 00917 Event_timed::compute_next_execution_time() 00918 00919 RETURN VALUE 00920 FALSE OK 00921 TRUE Error 00922 00923 NOTES 00924 The time is set in execute_at, if no more executions the latter is set to 00925 0000-00-00. 00926 */ 00927 00928 bool 00929 Event_timed::compute_next_execution_time() 00930 { 00931 TIME time_now; 00932 int tmp; 00933 00934 DBUG_ENTER("Event_timed::compute_next_execution_time"); 00935 DBUG_PRINT("enter", ("starts=%llu ends=%llu last_executed=%llu", 00936 TIME_to_ulonglong_datetime(&starts), 00937 TIME_to_ulonglong_datetime(&ends), 00938 TIME_to_ulonglong_datetime(&last_executed))); 00939 00940 if (status == Event_timed::DISABLED) 00941 { 00942 DBUG_PRINT("compute_next_execution_time", 00943 ("Event %s is DISABLED", name.str)); 00944 goto ret; 00945 } 00946 /* If one-time, no need to do computation */ 00947 if (!expression) 00948 { 00949 /* Let's check whether it was executed */ 00950 if (last_executed.year) 00951 { 00952 DBUG_PRINT("info",("One-time event %s.%s of was already executed", 00953 dbname.str, name.str, definer.str)); 00954 dropped= (on_completion == Event_timed::ON_COMPLETION_DROP); 00955 DBUG_PRINT("info",("One-time event will be dropped=%d.", dropped)); 00956 00957 status= Event_timed::DISABLED; 00958 status_changed= true; 00959 } 00960 goto ret; 00961 } 00962 00963 my_tz_UTC->gmt_sec_to_TIME(&time_now, current_thd->query_start()); 00964 00965 DBUG_PRINT("info",("NOW=[%llu]", TIME_to_ulonglong_datetime(&time_now))); 00966 00967 /* if time_now is after ends don't execute anymore */ 00968 if (!ends_null && (tmp= my_time_compare(&ends, &time_now)) == -1) 00969 { 00970 DBUG_PRINT("info", ("NOW after ENDS, don't execute anymore")); 00971 /* time_now is after ends. don't execute anymore */ 00972 set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME); 00973 execute_at_null= TRUE; 00974 if (on_completion == Event_timed::ON_COMPLETION_DROP) 00975 dropped= true; 00976 DBUG_PRINT("info", ("Dropped=%d", dropped)); 00977 status= Event_timed::DISABLED; 00978 status_changed= true; 00979 00980 goto ret; 00981 } 00982 00983 /* 00984 Here time_now is before or equals ends if the latter is set. 00985 Let's check whether time_now is before starts. 00986 If so schedule for starts. 00987 */ 00988 if (!starts_null && (tmp= my_time_compare(&time_now, &starts)) < 1) 00989 { 00990 if (tmp == 0 && my_time_compare(&starts, &last_executed) == 0) 00991 { 00992 /* 00993 time_now = starts = last_executed 00994 do nothing or we will schedule for second time execution at starts. 00995 */ 00996 } 00997 else 00998 { 00999 DBUG_PRINT("info", ("STARTS is future, NOW <= STARTS,sched for STARTS")); 01000 /* 01001 starts is in the future 01002 time_now before starts. Scheduling for starts 01003 */ 01004 execute_at= starts; 01005 execute_at_null= FALSE; 01006 goto ret; 01007 } 01008 } 01009 01010 if (!starts_null && !ends_null) 01011 { 01012 /* 01013 Both starts and m_ends are set and time_now is between them (incl.) 01014 If last_executed is set then increase with m_expression. The new TIME is 01015 after m_ends set execute_at to 0. And check for on_completion 01016 If not set then schedule for now. 01017 */ 01018 DBUG_PRINT("info", ("Both STARTS & ENDS are set")); 01019 if (!last_executed.year) 01020 { 01021 DBUG_PRINT("info", ("Not executed so far.")); 01022 } 01023 01024 { 01025 TIME next_exec; 01026 01027 if (get_next_time(&next_exec, &starts, &time_now, 01028 last_executed.year? &last_executed:&starts, 01029 expression, interval)) 01030 goto err; 01031 01032 /* There was previous execution */ 01033 if (my_time_compare(&ends, &next_exec) == -1) 01034 { 01035 DBUG_PRINT("info", ("Next execution of %s after ENDS. Stop executing.", 01036 name.str)); 01037 /* Next execution after ends. No more executions */ 01038 set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME); 01039 execute_at_null= TRUE; 01040 if (on_completion == Event_timed::ON_COMPLETION_DROP) 01041 dropped= true; 01042 status= Event_timed::DISABLED; 01043 status_changed= true; 01044 } 01045 else 01046 { 01047 DBUG_PRINT("info",("Next[%llu]",TIME_to_ulonglong_datetime(&next_exec))); 01048 execute_at= next_exec; 01049 execute_at_null= FALSE; 01050 } 01051 } 01052 goto ret; 01053 } 01054 else if (starts_null && ends_null) 01055 { 01056 /* starts is always set, so this is a dead branch !! */ 01057 DBUG_PRINT("info", ("Neither STARTS nor ENDS are set")); 01058 /* 01059 Both starts and m_ends are not set, so we schedule for the next 01060 based on last_executed. 01061 */ 01062 if (last_executed.year) 01063 { 01064 TIME next_exec; 01065 if (get_next_time(&next_exec, &starts, &time_now, &last_executed, 01066 expression, interval)) 01067 goto err; 01068 execute_at= next_exec; 01069 DBUG_PRINT("info",("Next[%llu]",TIME_to_ulonglong_datetime(&next_exec))); 01070 } 01071 else 01072 { 01073 /* last_executed not set. Schedule the event for now */ 01074 DBUG_PRINT("info", ("Execute NOW")); 01075 execute_at= time_now; 01076 } 01077 execute_at_null= FALSE; 01078 } 01079 else 01080 { 01081 /* either starts or m_ends is set */ 01082 if (!starts_null) 01083 { 01084 DBUG_PRINT("info", ("STARTS is set")); 01085 /* 01086 - starts is set. 01087 - starts is not in the future according to check made before 01088 Hence schedule for starts + m_expression in case last_executed 01089 is not set, otherwise to last_executed + m_expression 01090 */ 01091 if (!last_executed.year) 01092 { 01093 DBUG_PRINT("info", ("Not executed so far.")); 01094 } 01095 01096 { 01097 TIME next_exec; 01098 if (get_next_time(&next_exec, &starts, &time_now, 01099 last_executed.year? &last_executed:&starts, 01100 expression, interval)) 01101 goto err; 01102 execute_at= next_exec; 01103 DBUG_PRINT("info",("Next[%llu]",TIME_to_ulonglong_datetime(&next_exec))); 01104 } 01105 execute_at_null= FALSE; 01106 } 01107 else 01108 { 01109 /* this is a dead branch, because starts is always set !!! */ 01110 DBUG_PRINT("info", ("STARTS is not set. ENDS is set")); 01111 /* 01112 - m_ends is set 01113 - m_ends is after time_now or is equal 01114 Hence check for m_last_execute and increment with m_expression. 01115 If last_executed is not set then schedule for now 01116 */ 01117 01118 if (!last_executed.year) 01119 execute_at= time_now; 01120 else 01121 { 01122 TIME next_exec; 01123 01124 if (get_next_time(&next_exec, &starts, &time_now, &last_executed, 01125 expression, interval)) 01126 goto err; 01127 01128 if (my_time_compare(&ends, &next_exec) == -1) 01129 { 01130 DBUG_PRINT("info", ("Next execution after ENDS. Stop executing.")); 01131 set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME); 01132 execute_at_null= TRUE; 01133 status= Event_timed::DISABLED; 01134 status_changed= true; 01135 if (on_completion == Event_timed::ON_COMPLETION_DROP) 01136 dropped= true; 01137 } 01138 else 01139 { 01140 DBUG_PRINT("info", ("Next[%llu]", 01141 TIME_to_ulonglong_datetime(&next_exec))); 01142 execute_at= next_exec; 01143 execute_at_null= FALSE; 01144 } 01145 } 01146 } 01147 goto ret; 01148 } 01149 ret: 01150 DBUG_PRINT("info", ("ret=0")); 01151 DBUG_RETURN(false); 01152 err: 01153 DBUG_PRINT("info", ("ret=1")); 01154 DBUG_RETURN(true); 01155 } 01156 01157 01158 /* 01159 Set the internal last_executed TIME struct to now. NOW is the 01160 time according to thd->query_start(), so the THD's clock. 01161 01162 SYNOPSIS 01163 Event_timed::drop() 01164 thd thread context 01165 */ 01166 01167 void 01168 Event_timed::mark_last_executed(THD *thd) 01169 { 01170 TIME time_now; 01171 01172 thd->end_time(); 01173 my_tz_UTC->gmt_sec_to_TIME(&time_now, (my_time_t) thd->query_start()); 01174 01175 last_executed= time_now; /* was execute_at */ 01176 last_executed_changed= true; 01177 } 01178 01179 01180 /* 01181 Drops the event 01182 01183 SYNOPSIS 01184 Event_timed::drop() 01185 thd thread context 01186 01187 RETURN VALUE 01188 0 OK 01189 -1 Cannot open mysql.event 01190 -2 Cannot find the event in mysql.event (already deleted?) 01191 01192 others return code from SE in case deletion of the event row 01193 failed. 01194 */ 01195 01196 int 01197 Event_timed::drop(THD *thd) 01198 { 01199 uint tmp= 0; 01200 DBUG_ENTER("Event_timed::drop"); 01201 01202 DBUG_RETURN(db_drop_event(thd, this, false, &tmp)); 01203 } 01204 01205 01206 /* 01207 Saves status and last_executed_at to the disk if changed. 01208 01209 SYNOPSIS 01210 Event_timed::update_fields() 01211 thd - thread context 01212 01213 RETURN VALUE 01214 0 OK 01215 EVEX_OPEN_TABLE_FAILED Error while opening mysql.event for writing 01216 EVEX_WRITE_ROW_FAILED On error to write to disk 01217 01218 others return code from SE in case deletion of the event 01219 row failed. 01220 */ 01221 01222 bool 01223 Event_timed::update_fields(THD *thd) 01224 { 01225 TABLE *table; 01226 Open_tables_state backup; 01227 int ret; 01228 01229 DBUG_ENTER("Event_timed::update_time_fields"); 01230 01231 DBUG_PRINT("enter", ("name: %*s", name.length, name.str)); 01232 01233 /* No need to update if nothing has changed */ 01234 if (!(status_changed || last_executed_changed)) 01235 DBUG_RETURN(0); 01236 01237 thd->reset_n_backup_open_tables_state(&backup); 01238 01239 if (Events::open_event_table(thd, TL_WRITE, &table)) 01240 { 01241 ret= EVEX_OPEN_TABLE_FAILED; 01242 goto done; 01243 } 01244 01245 01246 if ((ret= evex_db_find_event_by_name(thd, dbname, name, table))) 01247 goto done; 01248 01249 store_record(table,record[1]); 01250 /* Don't update create on row update. */ 01251 table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; 01252 01253 if (last_executed_changed) 01254 { 01255 table->field[Events::FIELD_LAST_EXECUTED]->set_notnull(); 01256 table->field[Events::FIELD_LAST_EXECUTED]->store_time(&last_executed, 01257 MYSQL_TIMESTAMP_DATETIME); 01258 last_executed_changed= false; 01259 } 01260 if (status_changed) 01261 { 01262 table->field[Events::FIELD_STATUS]->set_notnull(); 01263 table->field[Events::FIELD_STATUS]->store((longlong)status, true); 01264 status_changed= false; 01265 } 01266 01267 if ((table->file->ha_update_row(table->record[1],table->record[0]))) 01268 ret= EVEX_WRITE_ROW_FAILED; 01269 01270 done: 01271 close_thread_tables(thd); 01272 thd->restore_backup_open_tables_state(&backup); 01273 01274 DBUG_RETURN(ret); 01275 } 01276 01277 01278 /* 01279 Get SHOW CREATE EVENT as string 01280 01281 SYNOPSIS 01282 Event_timed::get_create_event(THD *thd, String *buf) 01283 thd Thread 01284 buf String*, should be already allocated. CREATE EVENT goes inside. 01285 01286 RETURN VALUE 01287 0 OK 01288 EVEX_MICROSECOND_UNSUP Error (for now if mysql.event has been 01289 tampered and MICROSECONDS interval or 01290 derivative has been put there. 01291 */ 01292 01293 int 01294 Event_timed::get_create_event(THD *thd, String *buf) 01295 { 01296 int multipl= 0; 01297 char tmp_buff[128]; 01298 String expr_buf(tmp_buff, sizeof(tmp_buff), system_charset_info); 01299 expr_buf.length(0); 01300 01301 DBUG_ENTER("get_create_event"); 01302 DBUG_PRINT("ret_info",("body_len=[%d]body=[%s]", body.length, body.str)); 01303 01304 if (expression && Events::reconstruct_interval_expression(&expr_buf, interval, 01305 expression)) 01306 DBUG_RETURN(EVEX_MICROSECOND_UNSUP); 01307 01308 buf->append(STRING_WITH_LEN("CREATE EVENT ")); 01309 append_identifier(thd, buf, name.str, name.length); 01310 01311 buf->append(STRING_WITH_LEN(" ON SCHEDULE ")); 01312 if (expression) 01313 { 01314 buf->append(STRING_WITH_LEN("EVERY ")); 01315 buf->append(expr_buf); 01316 buf->append(' '); 01317 LEX_STRING *ival= &interval_type_to_name[interval]; 01318 buf->append(ival->str, ival->length); 01319 } 01320 else 01321 { 01322 char dtime_buff[20*2+32];/* +32 to make my_snprintf_{8bit|ucs2} happy */ 01323 buf->append(STRING_WITH_LEN("AT '")); 01324 /* 01325 Pass the buffer and the second param tells fills the buffer and 01326 returns the number of chars to copy. 01327 */ 01328 buf->append(dtime_buff, my_datetime_to_str(&execute_at, dtime_buff)); 01329 buf->append(STRING_WITH_LEN("'")); 01330 } 01331 01332 if (on_completion == Event_timed::ON_COMPLETION_DROP) 01333 buf->append(STRING_WITH_LEN(" ON COMPLETION NOT PRESERVE ")); 01334 else 01335 buf->append(STRING_WITH_LEN(" ON COMPLETION PRESERVE ")); 01336 01337 if (status == Event_timed::ENABLED) 01338 buf->append(STRING_WITH_LEN("ENABLE")); 01339 else 01340 buf->append(STRING_WITH_LEN("DISABLE")); 01341 01342 if (comment.length) 01343 { 01344 buf->append(STRING_WITH_LEN(" COMMENT ")); 01345 append_unescaped(buf, comment.str, comment.length); 01346 } 01347 buf->append(STRING_WITH_LEN(" DO ")); 01348 buf->append(body.str, body.length); 01349 01350 DBUG_RETURN(0); 01351 } 01352 01353 01354 /* 01355 Executes the event (the underlying sp_head object); 01356 01357 SYNOPSIS 01358 evex_fill_row() 01359 thd THD 01360 mem_root If != NULL use it to compile the event on it 01361 01362 RETURN VALUE 01363 0 success 01364 -99 No rights on this.dbname.str 01365 -100 event in execution (parallel execution is impossible) 01366 others retcodes of sp_head::execute_procedure() 01367 */ 01368 01369 int 01370 Event_timed::execute(THD *thd, MEM_ROOT *mem_root) 01371 { 01372 /* this one is local and not needed after exec */ 01373 Security_context security_ctx; 01374 int ret= 0; 01375 01376 DBUG_ENTER("Event_timed::execute"); 01377 DBUG_PRINT("info", (" EVEX EXECUTING event %s.%s [EXPR:%d]", 01378 dbname.str, name.str, (int) expression)); 01379 01380 VOID(pthread_mutex_lock(&this->LOCK_running)); 01381 if (running) 01382 { 01383 VOID(pthread_mutex_unlock(&this->LOCK_running)); 01384 DBUG_RETURN(-100); 01385 } 01386 running= true; 01387 VOID(pthread_mutex_unlock(&this->LOCK_running)); 01388 01389 if (!sphead && (ret= compile(thd, mem_root))) 01390 goto done; 01391 /* 01392 THD::~THD will clean this or if there is DROP DATABASE in the SP then 01393 it will be free there. It should not point to our buffer which is allocated 01394 on a mem_root. 01395 */ 01396 thd->db= my_strdup(dbname.str, MYF(0)); 01397 thd->db_length= dbname.length; 01398 if (!check_access(thd, EVENT_ACL,dbname.str, 0, 0, 0,is_schema_db(dbname.str))) 01399 { 01400 List<Item> empty_item_list; 01401 empty_item_list.empty(); 01402 if (thd->enable_slow_log) 01403 sphead->m_flags|= sp_head::LOG_SLOW_STATEMENTS; 01404 sphead->m_flags|= sp_head::LOG_GENERAL_LOG; 01405 01406 ret= sphead->execute_procedure(thd, &empty_item_list); 01407 } 01408 else 01409 { 01410 DBUG_PRINT("error", ("%s@%s has no rights on %s", definer_user.str, 01411 definer_host.str, dbname.str)); 01412 ret= -99; 01413 } 01414 01415 VOID(pthread_mutex_lock(&this->LOCK_running)); 01416 running= false; 01417 /* Will compile every time a new sp_head on different root */ 01418 free_sp(); 01419 VOID(pthread_mutex_unlock(&this->LOCK_running)); 01420 01421 done: 01422 /* 01423 1. Don't cache sphead if allocated on another mem_root 01424 2. Don't call security_ctx.destroy() because this will free our dbname.str 01425 name.str and definer.str 01426 */ 01427 if (mem_root && sphead) 01428 { 01429 delete sphead; 01430 sphead= 0; 01431 } 01432 DBUG_PRINT("info", (" EVEX EXECUTED event %s.%s [EXPR:%d]. RetCode=%d", 01433 dbname.str, name.str, (int) expression, ret)); 01434 01435 DBUG_RETURN(ret); 01436 } 01437 01438 01439 /* 01440 Frees the memory of the sp_head object we hold 01441 SYNOPSIS 01442 Event_timed::free_sp() 01443 */ 01444 01445 void 01446 Event_timed::free_sp() 01447 { 01448 delete sphead; 01449 sphead= 0; 01450 } 01451 01452 01453 /* 01454 Compiles an event before it's execution. Compiles the anonymous 01455 sp_head object held by the event 01456 01457 SYNOPSIS 01458 Event_timed::compile() 01459 thd thread context, used for memory allocation mostly 01460 mem_root if != NULL then this memory root is used for allocs 01461 instead of thd->mem_root 01462 01463 RETURN VALUE 01464 0 success 01465 EVEX_COMPILE_ERROR error during compilation 01466 EVEX_MICROSECOND_UNSUP mysql.event was tampered 01467 */ 01468 01469 int 01470 Event_timed::compile(THD *thd, MEM_ROOT *mem_root) 01471 { 01472 int ret= 0; 01473 MEM_ROOT *tmp_mem_root= 0; 01474 LEX *old_lex= thd->lex, lex; 01475 char *old_db; 01476 int old_db_length; 01477 char *old_query; 01478 uint old_query_len; 01479 ulong old_sql_mode= thd->variables.sql_mode; 01480 char create_buf[2048]; 01481 String show_create(create_buf, sizeof(create_buf), system_charset_info); 01482 CHARSET_INFO *old_character_set_client, 01483 *old_collation_connection, 01484 *old_character_set_results; 01485 Security_context *save_ctx; 01486 /* this one is local and not needed after exec */ 01487 Security_context security_ctx; 01488 01489 DBUG_ENTER("Event_timed::compile"); 01490 01491 show_create.length(0); 01492 01493 switch (get_create_event(thd, &show_create)) { 01494 case EVEX_MICROSECOND_UNSUP: 01495 sql_print_error("Scheduler"); 01496 DBUG_RETURN(EVEX_MICROSECOND_UNSUP); 01497 case 0: 01498 break; 01499 default: 01500 DBUG_ASSERT(0); 01501 } 01502 01503 old_character_set_client= thd->variables.character_set_client; 01504 old_character_set_results= thd->variables.character_set_results; 01505 old_collation_connection= thd->variables.collation_connection; 01506 01507 thd->variables.character_set_client= 01508 thd->variables.character_set_results= 01509 thd->variables.collation_connection= 01510 get_charset_by_csname("utf8", MY_CS_PRIMARY, MYF(MY_WME)); 01511 01512 thd->update_charset(); 01513 01514 DBUG_PRINT("info",("old_sql_mode=%d new_sql_mode=%d",old_sql_mode, sql_mode)); 01515 thd->variables.sql_mode= this->sql_mode; 01516 /* Change the memory root for the execution time */ 01517 if (mem_root) 01518 { 01519 tmp_mem_root= thd->mem_root; 01520 thd->mem_root= mem_root; 01521 } 01522 old_query_len= thd->query_length; 01523 old_query= thd->query; 01524 old_db= thd->db; 01525 old_db_length= thd->db_length; 01526 thd->db= dbname.str; 01527 thd->db_length= dbname.length; 01528 01529 thd->query= show_create.c_ptr(); 01530 thd->query_length= show_create.length(); 01531 DBUG_PRINT("info", ("query:%s",thd->query)); 01532 01533 change_security_context(thd, definer_user, definer_host, dbname, 01534 &security_ctx, &save_ctx); 01535 thd->lex= &lex; 01536 lex_start(thd, (uchar*)thd->query, thd->query_length); 01537 lex.et_compile_phase= TRUE; 01538 if (MYSQLparse((void *)thd) || thd->is_fatal_error) 01539 { 01540 DBUG_PRINT("error", ("error during compile or thd->is_fatal_error=%d", 01541 thd->is_fatal_error)); 01542 /* 01543 Free lex associated resources 01544 QQ: Do we really need all this stuff here? 01545 */ 01546 sql_print_error("error during compile of %s.%s or thd->is_fatal_error=%d", 01547 dbname.str, name.str, thd->is_fatal_error); 01548 if (lex.sphead) 01549 { 01550 if (&lex != thd->lex) 01551 thd->lex->sphead->restore_lex(thd); 01552 delete lex.sphead; 01553 lex.sphead= 0; 01554 } 01555 ret= EVEX_COMPILE_ERROR; 01556 goto done; 01557 } 01558 DBUG_PRINT("note", ("success compiling %s.%s", dbname.str, name.str)); 01559 01560 sphead= lex.et->sphead; 01561 sphead->m_db= dbname; 01562 01563 sphead->set_definer(definer.str, definer.length); 01564 sphead->set_info(0, 0, &lex.sp_chistics, sql_mode); 01565 sphead->optimize(); 01566 ret= 0; 01567 done: 01568 lex.et->free_sphead_on_delete= false; 01569 lex.et->deinit_mutexes(); 01570 01571 lex_end(&lex); 01572 restore_security_context(thd, save_ctx); 01573 DBUG_PRINT("note", ("return old data on its place. set back NAMES")); 01574 01575 thd->lex= old_lex; 01576 thd->query= old_query; 01577 thd->query_length= old_query_len; 01578 thd->db= old_db; 01579 01580 thd->variables.sql_mode= old_sql_mode; 01581 thd->variables.character_set_client= old_character_set_client; 01582 thd->variables.character_set_results= old_character_set_results; 01583 thd->variables.collation_connection= old_collation_connection; 01584 thd->update_charset(); 01585 01586 /* Change the memory root for the execution time. */ 01587 if (mem_root) 01588 thd->mem_root= tmp_mem_root; 01589 01590 DBUG_RETURN(ret); 01591 } 01592 01593 01594 extern pthread_attr_t connection_attrib; 01595 01596 /* 01597 Checks whether is possible and forks a thread. Passes self as argument. 01598 01599 RETURN VALUE 01600 EVENT_EXEC_STARTED OK 01601 EVENT_EXEC_ALREADY_EXEC Thread not forked, already working 01602 EVENT_EXEC_CANT_FORK Unable to spawn thread (error) 01603 */ 01604 01605 int 01606 Event_timed::spawn_now(void * (*thread_func)(void*), void *arg) 01607 { 01608 THD *thd= current_thd; 01609 int ret= EVENT_EXEC_STARTED; 01610 DBUG_ENTER("Event_timed::spawn_now"); 01611 DBUG_PRINT("info", ("[%s.%s]", dbname.str, name.str)); 01612 01613 VOID(pthread_mutex_lock(&this->LOCK_running)); 01614 01615 DBUG_PRINT("info", ("SCHEDULER: execute_at of %s is %lld", name.str, 01616 TIME_to_ulonglong_datetime(&execute_at))); 01617 mark_last_executed(thd); 01618 if (compute_next_execution_time()) 01619 { 01620 sql_print_error("SCHEDULER: Error while computing time of %s.%s . " 01621 "Disabling after execution.", dbname.str, name.str); 01622 status= DISABLED; 01623 } 01624 DBUG_PRINT("evex manager", ("[%10s] next exec at [%llu]", name.str, 01625 TIME_to_ulonglong_datetime(&execute_at))); 01626 /* 01627 1. For one-time event : year is > 0 and expression is 0 01628 2. For recurring, expression is != -=> check execute_at_null in this case 01629 */ 01630 if ((execute_at.year && !expression) || execute_at_null) 01631 { 01632 sql_print_information("SCHEDULER: [%s.%s of %s] no more executions " 01633 "after this one", dbname.str, name.str, 01634 definer.str); 01635 flags |= EVENT_EXEC_NO_MORE | EVENT_FREE_WHEN_FINISHED; 01636 } 01637 01638 update_fields(thd); 01639 01640 if (!in_spawned_thread) 01641 { 01642 pthread_t th; 01643 in_spawned_thread= true; 01644 01645 if (pthread_create(&th, &connection_attrib, thread_func, arg)) 01646 { 01647 DBUG_PRINT("info", ("problem while spawning thread")); 01648 ret= EVENT_EXEC_CANT_FORK; 01649 in_spawned_thread= false; 01650 } 01651 } 01652 else 01653 { 01654 DBUG_PRINT("info", ("already in spawned thread. skipping")); 01655 ret= EVENT_EXEC_ALREADY_EXEC; 01656 } 01657 VOID(pthread_mutex_unlock(&this->LOCK_running)); 01658 01659 DBUG_RETURN(ret); 01660 } 01661 01662 01663 bool 01664 Event_timed::spawn_thread_finish(THD *thd) 01665 { 01666 bool should_free; 01667 DBUG_ENTER("Event_timed::spawn_thread_finish"); 01668 VOID(pthread_mutex_lock(&LOCK_running)); 01669 in_spawned_thread= false; 01670 DBUG_PRINT("info", ("Sending COND_finished for thread %d", thread_id)); 01671 thread_id= 0; 01672 if (dropped) 01673 drop(thd); 01674 pthread_cond_broadcast(&COND_finished); 01675 should_free= flags & EVENT_FREE_WHEN_FINISHED; 01676 VOID(pthread_mutex_unlock(&LOCK_running)); 01677 DBUG_RETURN(should_free); 01678 } 01679 01680 01681 /* 01682 Kills a running event 01683 SYNOPSIS 01684 Event_timed::kill_thread() 01685 01686 RETURN VALUE 01687 0 OK 01688 -1 EVEX_CANT_KILL 01689 !0 Error 01690 */ 01691 01692 int 01693 Event_timed::kill_thread(THD *thd) 01694 { 01695 int ret= 0; 01696 DBUG_ENTER("Event_timed::kill_thread"); 01697 pthread_mutex_lock(&LOCK_running); 01698 DBUG_PRINT("info", ("thread_id=%lu", thread_id)); 01699 01700 if (thread_id == thd->thread_id) 01701 { 01702 /* 01703 We don't kill ourselves in cases like : 01704 alter event e_43 do alter event e_43 do set @a = 4 because 01705 we will never receive COND_finished. 01706 */ 01707 DBUG_PRINT("info", ("It's not safe to kill ourselves in self altering queries")); 01708 ret= EVEX_CANT_KILL; 01709 } 01710 else if (thread_id && !(ret= kill_one_thread(thd, thread_id, false))) 01711 { 01712 thd->enter_cond(&COND_finished, &LOCK_running, "Waiting for finished"); 01713 DBUG_PRINT("info", ("Waiting for COND_finished from thread %d", thread_id)); 01714 while (thread_id) 01715 pthread_cond_wait(&COND_finished, &LOCK_running); 01716 01717 DBUG_PRINT("info", ("Got COND_finished")); 01718 /* This will implicitly unlock LOCK_running. Hence we return before that */ 01719 thd->exit_cond(""); 01720 01721 DBUG_RETURN(0); 01722 } 01723 else if (!thread_id && in_spawned_thread) 01724 { 01725 /* 01726 Because the manager thread waits for the forked thread to update thread_id 01727 this situation is impossible. 01728 */ 01729 DBUG_ASSERT(0); 01730 } 01731 pthread_mutex_unlock(&LOCK_running); 01732 DBUG_PRINT("exit", ("%d", ret)); 01733 DBUG_RETURN(ret); 01734 } 01735 01736 01737 /* 01738 Checks whether two events have the same name 01739 01740 SYNOPSIS 01741 event_timed_name_equal() 01742 01743 RETURN VALUE 01744 TRUE names are equal 01745 FALSE names are not equal 01746 */ 01747 01748 bool 01749 event_timed_name_equal(Event_timed *et, LEX_STRING *name) 01750 { 01751 return !sortcmp_lex_string(et->name, *name, system_charset_info); 01752 } 01753 01754 01755 /* 01756 Checks whether two events are in the same schema 01757 01758 SYNOPSIS 01759 event_timed_db_equal() 01760 01761 RETURN VALUE 01762 TRUE schemas are equal 01763 FALSE schemas are not equal 01764 */ 01765 01766 bool 01767 event_timed_db_equal(Event_timed *et, LEX_STRING *db) 01768 { 01769 return !sortcmp_lex_string(et->dbname, *db, system_charset_info); 01770 } 01771 01772 01773 /* 01774 Checks whether two events have the same definer 01775 01776 SYNOPSIS 01777 event_timed_definer_equal() 01778 01779 Returns 01780 TRUE definers are equal 01781 FALSE definers are not equal 01782 */ 01783 01784 bool 01785 event_timed_definer_equal(Event_timed *et, LEX_STRING *definer) 01786 { 01787 return !sortcmp_lex_string(et->definer, *definer, system_charset_info); 01788 } 01789 01790 01791 /* 01792 Checks whether two events are equal by identifiers 01793 01794 SYNOPSIS 01795 event_timed_identifier_equal() 01796 01797 RETURN VALUE 01798 TRUE equal 01799 FALSE not equal 01800 */ 01801 01802 bool 01803 event_timed_identifier_equal(Event_timed *a, Event_timed *b) 01804 { 01805 return event_timed_name_equal(a, &b->name) && 01806 event_timed_db_equal(a, &b->dbname) && 01807 event_timed_definer_equal(a, &b->definer); 01808 } 01809 01810 01811 /* 01812 Switches the security context 01813 SYNOPSIS 01814 change_security_context() 01815 thd Thread 01816 user The user 01817 host The host of the user 01818 db The schema for which the security_ctx will be loaded 01819 s_ctx Security context to load state into 01820 backup Where to store the old context 01821 01822 RETURN VALUE 01823 0 - OK 01824 1 - Error (generates error too) 01825 */ 01826 01827 bool 01828 change_security_context(THD *thd, LEX_STRING user, LEX_STRING host, 01829 LEX_STRING db, Security_context *s_ctx, 01830 Security_context **backup) 01831 { 01832 DBUG_ENTER("change_security_context"); 01833 DBUG_PRINT("info",("%s@%s@%s", user.str, host.str, db.str)); 01834 #ifndef NO_EMBEDDED_ACCESS_CHECKS 01835 s_ctx->init(); 01836 *backup= 0; 01837 if (acl_getroot_no_password(s_ctx, user.str, host.str, host.str, db.str)) 01838 { 01839 my_error(ER_NO_SUCH_USER, MYF(0), user.str, host.str); 01840 DBUG_RETURN(TRUE); 01841 } 01842 *backup= thd->security_ctx; 01843 thd->security_ctx= s_ctx; 01844 #endif 01845 DBUG_RETURN(FALSE); 01846 } 01847 01848 01849 /* 01850 Restores the security context 01851 SYNOPSIS 01852 restore_security_context() 01853 thd - thread 01854 backup - switch to this context 01855 */ 01856 01857 void 01858 restore_security_context(THD *thd, Security_context *backup) 01859 { 01860 DBUG_ENTER("restore_security_context"); 01861 #ifndef NO_EMBEDDED_ACCESS_CHECKS 01862 if (backup) 01863 thd->security_ctx= backup; 01864 #endif 01865 DBUG_VOID_RETURN; 01866 }
1.4.7

