diff --git a/mysql-test/lib/init_db.sql b/mysql-test/lib/init_db.sql index 4ba7184d551..f075a1ebe93 100644 --- a/mysql-test/lib/init_db.sql +++ b/mysql-test/lib/init_db.sql @@ -22,6 +22,7 @@ CREATE TABLE db ( Create_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Alter_routine_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, Execute_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, + Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL, PRIMARY KEY Host (Host,Db,User), KEY User (User) ) engine=MyISAM @@ -29,8 +30,8 @@ CHARACTER SET utf8 COLLATE utf8_bin comment='Database privileges'; -INSERT INTO db VALUES ('%','test','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N'); -INSERT INTO db VALUES ('%','test\_%','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N'); +INSERT INTO db VALUES ('%','test','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N','Y'); +INSERT INTO db VALUES ('%','test\_%','','Y','Y','Y','Y','Y','Y','N','Y','Y','Y','Y','Y','Y','Y','Y','N','N','Y'); CREATE TABLE host ( @@ -570,26 +571,26 @@ CREATE TABLE proc ( CREATE TABLE event ( - 'db' VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', - 'name' VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', - 'body' longblob NOT NULL, - 'definer' VARCHAR(77) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', - 'execute_at' DATETIME default NULL, - 'transient_expression' int(11) default NULL, - 'interval_type' ENUM('YEAR','QUARTER','MONTH','DAY','HOUR','MINUTE','WEEK', + db VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', + name VARCHAR(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', + body longblob NOT NULL, + definer VARCHAR(77) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', + execute_at DATETIME default NULL, + transient_expression int(11) default NULL, + interval_type ENUM('YEAR','QUARTER','MONTH','DAY','HOUR','MINUTE','WEEK', 'SECOND','MICROSECOND', 'YEAR_MONTH','DAY_HOUR', 'DAY_MINUTE','DAY_SECOND', 'HOUR_MINUTE','HOUR_SECOND', 'MINUTE_SECOND','DAY_MICROSECOND', 'HOUR_MICROSECOND','MINUTE_MICROSECOND', 'SECOND_MICROSECOND') default NULL, - 'created' TIMESTAMP NOT NULL default '0000-00-00 00:00:00', - 'modified' TIMESTAMP NOT NULL default '0000-00-00 00:00:00', - 'last_executed' DATETIME default NULL, - 'starts' DATETIME default NULL, - 'ends' DATETIME default NULL, - 'status' ENUM('ENABLED','DISABLED') NOT NULL default 'ENABLED', - 'on_completion' ENUM('DROP','PRESERVE') NOT NULL default 'DROP', - 'comment' varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', - PRIMARY KEY ('db','name') + created TIMESTAMP NOT NULL, + modified TIMESTAMP NOT NULL, + last_executed DATETIME default NULL, + starts DATETIME default NULL, + ends DATETIME default NULL, + status ENUM('ENABLED','DISABLED') NOT NULL default 'ENABLED', + on_completion ENUM('DROP','PRESERVE') NOT NULL default 'DROP', + comment varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', + PRIMARY KEY (db, name) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT 'Events'; diff --git a/mysql-test/r/events.result b/mysql-test/r/events.result new file mode 100644 index 00000000000..5816f9888a0 --- /dev/null +++ b/mysql-test/r/events.result @@ -0,0 +1,21 @@ +use test; +drop event if exists event1; +Warnings: +Note 1305 Event event1 does not exist +create event event1 on schedule every 15 minute starts now() ends date_add(now(), interval 5 hour) DO begin end; +alter event event1 rename to event2; +alter event event2 disable; +drop event event2; +create event event2 on schedule every 2 second starts now() ends date_add(now(), interval 5 hour) comment "some" DO begin end; +drop event event2; +create table t_event3 (a int, b float); +drop event if exists event3; +Warnings: +Note 1305 Event event3 does not exist +create event event3 on schedule every 50 + 10 minute starts date_add("20010101", interval 5 minute) ends date_add("20151010", interval 5 day) comment "portokala_comment" DO insert into t_event3 values (unix_timestamp(), rand()); +set max_allowed_packet=128000000; +select count(*) from t_event3; +count(*) +0 +drop event event3; +drop table t_event3; diff --git a/mysql-test/t/events.test b/mysql-test/t/events.test index 9285b38dc6b..bba34947ecd 100644 --- a/mysql-test/t/events.test +++ b/mysql-test/t/events.test @@ -1,5 +1,4 @@ -create database events_test; -use events_test; +use test; drop event if exists event1; create event event1 on schedule every 15 minute starts now() ends date_add(now(), interval 5 hour) DO begin end; alter event event1 rename to event2; @@ -13,7 +12,6 @@ create table t_event3 (a int, b float); drop event if exists event3; create event event3 on schedule every 50 + 10 minute starts date_add("20010101", interval 5 minute) ends date_add("20151010", interval 5 day) comment "portokala_comment" DO insert into t_event3 values (unix_timestamp(), rand()); set max_allowed_packet=128000000; -select sha1(space(9999999)); select count(*) from t_event3; drop event event3; -drop database events_test; +drop table t_event3; diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql index 2949049afe8..255f83e473e 100644 --- a/scripts/mysql_fix_privilege_tables.sql +++ b/scripts/mysql_fix_privilege_tables.sql @@ -562,5 +562,6 @@ CREATE TABLE event ( # EVENT privilege # -ALTER TABLE mysql.user add Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL AFTER Create_user_priv; -ALTER TABLE mysql.db add Event_priv enum('N','Y') COLLATE utf8_general_ci DEFAULT 'N' NOT NULL; +ALTER TABLE mysql.user add Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL AFTER Create_user_priv; +ALTER TABLE mysql.db add Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL; + diff --git a/sql/event.cc b/sql/event.cc index 806780e5097..5425b676b60 100644 --- a/sql/event.cc +++ b/sql/event.cc @@ -652,6 +652,7 @@ evex_load_and_compile_event(THD * thd, sp_name *spn, bool use_lock) int ret= 0; MEM_ROOT *tmp_mem_root; event_timed *ett; + Open_tables_state backup; DBUG_ENTER("db_load_and_compile_event"); DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str)); @@ -659,10 +660,12 @@ evex_load_and_compile_event(THD * thd, sp_name *spn, bool use_lock) tmp_mem_root= thd->mem_root; thd->mem_root= &evex_mem_root; + thd->reset_n_backup_open_tables_state(&backup); // no need to use my_error() here because db_find_event() has done it if ((ret= db_find_event(thd, spn, &ett, NULL))) goto done; + thd->restore_backup_open_tables_state(&backup); /* allocate on evex_mem_root. if you call without evex_mem_root then sphead will not be cleared! diff --git a/sql/event_executor.cc b/sql/event_executor.cc index 623e45bf118..9578cd936ea 100644 --- a/sql/event_executor.cc +++ b/sql/event_executor.cc @@ -30,7 +30,7 @@ #define DBUG_FAULTY_THR2 extern ulong thread_created; - +extern const char *my_localhost; pthread_mutex_t LOCK_event_arrays, LOCK_workers_count, @@ -125,6 +125,7 @@ init_event_thread(THD* thd) DBUG_ENTER("init_event_thread"); thd->client_capabilities= 0; thd->security_ctx->skip_grants(); + thd->security_ctx->host= (char*)my_localhost; my_net_init(&thd->net, 0); thd->net.read_timeout = slave_net_timeout; thd->slave_thread= 0; @@ -211,6 +212,7 @@ event_executor_main(void *arg) if (evex_load_events_from_db(thd)) goto err; + thd->security_ctx->user= my_strdup("event_scheduler", MYF(0)); THD_CHECK_SENTRY(thd); /* Read queries from the IO/THREAD until this thread is killed */ evex_main_thread_id= thd->thread_id; @@ -254,8 +256,8 @@ event_executor_main(void *arg) VOID(pthread_mutex_unlock(&LOCK_event_arrays)); if (t2sleep > 0) { - sql_print_information("Sleeping for %d seconds.", t2sleep); - printf("\nWHEN=%llu NOW=%llu\n", TIME_to_ulonglong_datetime(&et->execute_at), TIME_to_ulonglong_datetime(&time_now)); +// sql_print_information("Sleeping for %d seconds.", t2sleep); +// printf("\nWHEN=%llu NOW=%llu\n", TIME_to_ulonglong_datetime(&et->execute_at), TIME_to_ulonglong_datetime(&time_now)); /* We sleep t2sleep seconds but we check every second whether this thread has been killed, or there is new candidate @@ -264,7 +266,7 @@ event_executor_main(void *arg) evex_queue_num_elements(EVEX_EQ_NAME) && (evex_queue_first_element(&EVEX_EQ_NAME, event_timed*) == et)) my_sleep(1000000); - sql_print_information("Finished sleeping"); +// sql_print_information("Finished sleeping"); } if (!event_executor_running_global_var) continue; @@ -297,9 +299,9 @@ event_executor_main(void *arg) pthread_t th; DBUG_PRINT("info", (" Spawning a thread %d", ++iter_num)); - sql_print_information(" Spawning a thread %d", ++iter_num); +// sql_print_information(" Spawning a thread %d", ++iter_num); #ifndef DBUG_FAULTY_THR - sql_print_information(" Thread is not debuggable!"); +// sql_print_information(" Thread is not debuggable!"); if (pthread_create(&th, NULL, event_executor_worker, (void*)et)) { sql_print_error("Problem while trying to create a thread"); @@ -442,20 +444,18 @@ event_executor_worker(void *event_void) strxnmov(thd->security_ctx->priv_host, sizeof(thd->security_ctx->priv_host), event->definer_host.str, NullS); - thd->security_ctx->priv_user= event->definer_user.str; + thd->security_ctx->user= thd->security_ctx->priv_user= my_strdup(event->definer_user.str, MYF(0)); thd->db= event->dbname.str; if (!check_access(thd, EVENT_ACL, event->dbname.str, 0, 0, 0, is_schema_db(event->dbname.str))) { - char exec_time[200]; int ret; - my_TIME_to_str(&event->execute_at, exec_time); - DBUG_PRINT("info", (" EVEX EXECUTING event for event %s.%s [EXPR:%d][EXECUTE_AT:%s]", event->dbname.str, event->name.str,(int) event->expression, exec_time)); - sql_print_information(" EVEX EXECUTING event for event %s.%s [EXPR:%d][EXECUTE_AT:%s]", event->dbname.str, event->name.str,(int) event->expression, exec_time); + DBUG_PRINT("info", (" EVEX EXECUTING event for event %s.%s [EXPR:%d]", event->dbname.str, event->name.str,(int) event->expression)); + sql_print_information(" EVEX EXECUTING event for event %s.%s [EXPR:%d]", event->dbname.str, event->name.str,(int) event->expression); ret= event->execute(thd, &worker_mem_root); - sql_print_information(" EVEX EXECUTED event for event %s.%s [EXPR:%d][EXECUTE_AT:%s]. RetCode=%d", event->dbname.str, event->name.str,(int) event->expression, exec_time, ret); - DBUG_PRINT("info", (" EVEX EXECUTED event for event %s.%s [EXPR:%d][EXECUTE_AT:%s]", event->dbname.str, event->name.str,(int) event->expression, exec_time)); + sql_print_information(" EVEX EXECUTED event for event %s.%s [EXPR:%d]. RetCode=%d", event->dbname.str, event->name.str,(int) event->expression, ret); + DBUG_PRINT("info", (" EVEX EXECUTED event for event %s.%s [EXPR:%d]. RetCode=%d", event->dbname.str, event->name.str,(int) event->expression, ret)); } thd->db= 0; @@ -505,6 +505,7 @@ evex_load_events_from_db(THD *thd) READ_RECORD read_record_info; MYSQL_LOCK *lock; int ret= -1; + uint count= 0; DBUG_ENTER("evex_load_events_from_db"); @@ -555,6 +556,7 @@ evex_load_events_from_db(THD *thd) evex_queue_insert(&EVEX_EQ_NAME, (EVEX_PTOQEL) et); DBUG_PRINT("evex_load_events_from_db", ("%p %*s", et, et->name.length,et->name.str)); + count++; } ret= 0; @@ -566,8 +568,8 @@ end: thd->version--; // Force close to free memory close_thread_tables(thd); - - DBUG_PRINT("info", ("Finishing with status code %d", ret)); + sql_print_information("Scheduler loaded %d events", count); + DBUG_PRINT("info", ("Finishing with status code %d. Loaded %d events", ret, count)); DBUG_RETURN(ret); } diff --git a/sql/event_timed.cc b/sql/event_timed.cc index 747eab4558c..aa22696b27f 100644 --- a/sql/event_timed.cc +++ b/sql/event_timed.cc @@ -807,7 +807,6 @@ event_timed::get_show_create_event(THD *thd, uint *length) *length= len; - sql_print_information("%d %d[%s]", len, dst-ret, ret); return ret; } @@ -938,7 +937,7 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root) goto done; } - sphead= lex.sphead; + sphead= lex.et->sphead; sphead->m_db= dbname; //copy also chistics since they will vanish otherwise we get 0x0 pointer // Todo : Handle sql_mode !! @@ -947,6 +946,7 @@ event_timed::compile(THD *thd, MEM_ROOT *mem_root) sphead->optimize(); ret= 0; done: + lex.et->free_sphead_on_delete= false; delete lex.et; lex_end(&lex); thd->lex= old_lex; diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 90d1ec38e64..71ba0fce4a9 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -960,8 +960,12 @@ int sp_head::execute(THD *thd) m_first_instance->m_first_free_instance= m_next_cached_sp; DBUG_PRINT("info", ("first free for 0x%lx ++: 0x%lx->0x%lx, level: %lu, flags %x", (ulong)m_first_instance, this, m_next_cached_sp, - m_next_cached_sp->m_recursion_level, - m_next_cached_sp->m_flags)); + (m_next_cached_sp ? + m_next_cached_sp->m_recursion_level : + 0), + (m_next_cached_sp ? + m_next_cached_sp->m_flags : + 0))); /* Check that if there are not any instances after this one then pointer to the last instance points on this instance or if there are diff --git a/sql/sql_acl.h b/sql/sql_acl.h index 44e42b961a2..993fa991eab 100644 --- a/sql/sql_acl.h +++ b/sql/sql_acl.h @@ -97,17 +97,20 @@ #define DB_CHUNK3 (CREATE_VIEW_ACL | SHOW_VIEW_ACL | \ CREATE_PROC_ACL | ALTER_PROC_ACL ) #define DB_CHUNK4 (EXECUTE_ACL) +#define DB_CHUNK5 (EVENT_ACL) #define fix_rights_for_db(A) (((A) & DB_CHUNK0) | \ (((A) << 4) & DB_CHUNK1) | \ (((A) << 6) & DB_CHUNK2) | \ (((A) << 9) & DB_CHUNK3) | \ - (((A) << 2) & DB_CHUNK4)) + (((A) << 2) & DB_CHUNK4))| \ + (((A) << 9) & DB_CHUNK5) #define get_rights_for_db(A) (((A) & DB_CHUNK0) | \ (((A) & DB_CHUNK1) >> 4) | \ (((A) & DB_CHUNK2) >> 6) | \ (((A) & DB_CHUNK3) >> 9) | \ - (((A) & DB_CHUNK4) >> 2)) + (((A) & DB_CHUNK4) >> 2))| \ + (((A) & DB_CHUNK5) >> 9) #define TBL_CHUNK0 DB_CHUNK0 #define TBL_CHUNK1 DB_CHUNK1 #define TBL_CHUNK2 (CREATE_VIEW_ACL | SHOW_VIEW_ACL) diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 3a729ddd9fa..c21d62952bf 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3704,10 +3704,9 @@ end_with_restore_list: /* lex->unit.cleanup() is called outside, no need to call it here */ } while (0); + lex->et->free_sphead_on_delete= true; delete lex->et; - delete lex->sphead; lex->et= 0; - lex->sphead= 0; break; } case SQLCOM_SHOW_CREATE_EVENT: @@ -5658,6 +5657,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length) } if (thd->lex->et) { + thd->lex->et->free_sphead_on_delete= true; delete thd->lex->et; thd->lex->et= NULL; } @@ -5698,6 +5698,7 @@ void mysql_parse(THD *thd, char *inBuf, uint length) } if (thd->lex->et) { + thd->lex->et->free_sphead_on_delete= true; delete thd->lex->et; thd->lex->et= NULL; } diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index 4b3e694b911..488eee86627 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -109,6 +109,7 @@ inline Item *is_truth_value(Item *A, bool v1, bool v2) struct { int vars, conds, hndlrs, curs; } spblock; sp_name *spname; struct st_lex *lex; + sp_head *sphead; } %{ @@ -1345,8 +1346,6 @@ create: if (!lex->et_compile_phase) lex->et->init_name(YYTHD, $4); - - lex->sphead= 0;//defensive programming } ON SCHEDULE_SYM ev_schedule_time ev_on_completion @@ -1482,33 +1481,46 @@ ev_sql_stmt: { LEX *lex= Lex; sp_head *sp; - - if (!(sp= new sp_head())) - YYABORT; - - sp->reset_thd_mem_root(YYTHD); - sp->init(lex); + + $$= lex->sphead; - sp->m_type= TYPE_ENUM_PROCEDURE; - lex->sphead= sp; + if (!lex->sphead) + { + if (!(sp= new sp_head())) + YYABORT; - bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); - lex->sphead->m_chistics= &lex->sp_chistics; + sp->reset_thd_mem_root(YYTHD); + sp->init(lex); + + sp->m_type= TYPE_ENUM_PROCEDURE; + + lex->sphead= sp; + + bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics)); + lex->sphead->m_chistics= &lex->sp_chistics; - lex->sphead->m_body_begin= lex->ptr; + lex->sphead->m_body_begin= lex->ptr; + } + if (!lex->et_compile_phase) lex->et->body_begin= lex->ptr; } ev_sql_stmt_inner { LEX *lex=Lex; - sp_head *sp= lex->sphead; - // return back to the original memory root ASAP - sp->init_strings(YYTHD, lex, NULL); - sp->restore_thd_mem_root(YYTHD); + + if (!$1) + { + sp_head *sp= lex->sphead; + // return back to the original memory root ASAP + sp->init_strings(YYTHD, lex, NULL); + sp->restore_thd_mem_root(YYTHD); - lex->sp_chistics.suid= SP_IS_SUID;//always the definer! + lex->sp_chistics.suid= SP_IS_SUID;//always the definer! + lex->et->sphead= lex->sphead; + lex->sphead= NULL; + } if (!lex->et_compile_phase) { lex->et->init_body(YYTHD); @@ -4223,7 +4235,8 @@ alter: } lex->spname= 0;//defensive programming - et= new event_timed();// implicitly calls event_timed::init() + if (!(et= new event_timed()))// implicitly calls event_timed::init() + YYABORT; lex->et = et; et->init_name(YYTHD, $3); @@ -4235,11 +4248,6 @@ alter: $$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES; YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES; - /* - defensive. in sql_parse.cc it is checked whether is not null - and then deleted - */ - lex->sphead= 0; } ev_on_schedule ev_rename_to