Commit dd31d457 authored by andrey@lmy004's avatar andrey@lmy004

WL #3337 (Events new architecture)

Final stroke, events should be loaded from disk on server startup.
Also check the validity of their bodies if possible during loading.
parent 3f4e1f5c
create database if not exists mysqltest_events_test;
use mysqltest_events_test;
set global event_scheduler=2;
create table execution_log(name char(10));
create event abc1 on schedule every 1 second do insert into execution_log value('abc1');
create event abc2 on schedule every 1 second do insert into execution_log value('abc2');
create event abc3 on schedule every 1 second do insert into execution_log value('abc3');
insert into mysql.event values ('db1','bad','select 42','root@localhost',NULL,1000,'MICROSECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment1');
insert into mysql.event values ('db1','bad2','sect','root@localhost',NULL,1000,'SECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment2');
"Now we restart the server"
use mysqltest_events_test;
"Should get 0 rows because the queue aborted run
select distinct name from execution_log order by name;
name
delete from mysql.event where name like 'bad%';
"Now restart the server again"
use mysqltest_events_test;
"Should get 3 rows : abc1, abc2, abc3
select distinct name from execution_log order by name;
name
drop event abc1;
drop event abc2;
drop event abc3;
drop table execution_log;
drop database mysqltest_events_test;
# Can't test with embedded server that doesn't support grants
-- source include/not_embedded.inc
--disable_warnings
create database if not exists mysqltest_events_test;
--enable_warnings
use mysqltest_events_test;
set global event_scheduler=2;
create table execution_log(name char(10));
create event abc1 on schedule every 1 second do insert into execution_log value('abc1');
create event abc2 on schedule every 1 second do insert into execution_log value('abc2');
create event abc3 on schedule every 1 second do insert into execution_log value('abc3');
insert into mysql.event values ('db1','bad','select 42','root@localhost',NULL,1000,'MICROSECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment1');
insert into mysql.event values ('db1','bad2','sect','root@localhost',NULL,1000,'SECOND','2006-05-05 17:39:11','2006-05-05 17:39:20','2016-05-05 15:39:24','2016-05-05 15:39:11',NULL,'ENABLED','DROP','','comment2');
--echo "Now we restart the server"
# Can't test with embedded server that doesn't support grants
-- source include/not_embedded.inc
use mysqltest_events_test;
--sleep 1.5
--echo "Should get 0 rows because the queue aborted run
select distinct name from execution_log order by name;
delete from mysql.event where name like 'bad%';
--echo "Now restart the server again"
# Can't test with embedded server that doesn't support grants
-- source include/not_embedded.inc
use mysqltest_events_test;
--sleep 2
--echo "Should get 3 rows : abc1, abc2, abc3
select distinct name from execution_log order by name;
drop event abc1;
drop event abc2;
drop event abc3;
drop table execution_log;
drop database mysqltest_events_test;
...@@ -731,7 +731,7 @@ Event_timed::~Event_timed() ...@@ -731,7 +731,7 @@ Event_timed::~Event_timed()
*/ */
Event_job_data::Event_job_data(): Event_job_data::Event_job_data():
thd(NULL), sphead(0), sql_mode(0) thd(NULL), sphead(NULL), sql_mode(0)
{ {
} }
...@@ -745,7 +745,10 @@ Event_job_data::Event_job_data(): ...@@ -745,7 +745,10 @@ Event_job_data::Event_job_data():
Event_job_data::~Event_job_data() Event_job_data::~Event_job_data()
{ {
free_sp(); DBUG_ENTER("Event_job_data::~Event_job_data");
delete sphead;
sphead= NULL;
DBUG_VOID_RETURN;
} }
...@@ -1605,20 +1608,6 @@ Event_job_data::get_fake_create_event(THD *thd, String *buf) ...@@ -1605,20 +1608,6 @@ Event_job_data::get_fake_create_event(THD *thd, String *buf)
} }
/*
Frees the memory of the sp_head object we hold
SYNOPSIS
Event_job_data::free_sp()
*/
void
Event_job_data::free_sp()
{
delete sphead;
sphead= NULL;
}
/* /*
Compiles an event before it's execution. Compiles the anonymous Compiles an event before it's execution. Compiles the anonymous
sp_head object held by the event sp_head object held by the event
...@@ -1651,9 +1640,7 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root) ...@@ -1651,9 +1640,7 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root)
CHARSET_INFO *old_character_set_client, CHARSET_INFO *old_character_set_client,
*old_collation_connection, *old_collation_connection,
*old_character_set_results; *old_character_set_results;
Security_context *save_ctx; Security_context save_ctx;
/* this one is local and not needed after exec */
Security_context security_ctx;
DBUG_ENTER("Event_job_data::compile"); DBUG_ENTER("Event_job_data::compile");
...@@ -1699,10 +1686,9 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root) ...@@ -1699,10 +1686,9 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root)
thd->query_length= show_create.length(); thd->query_length= show_create.length();
DBUG_PRINT("info", ("query:%s",thd->query)); DBUG_PRINT("info", ("query:%s",thd->query));
thd->change_security_context(definer_user, definer_host, dbname, thd->change_security_context(definer_user, definer_host, dbname, &save_ctx);
&security_ctx, &save_ctx);
thd->lex= &lex; thd->lex= &lex;
lex_start(thd, (uchar*)thd->query, thd->query_length); mysql_init_query(thd, (uchar*) thd->query, thd->query_length);
if (MYSQLparse((void *)thd) || thd->is_fatal_error) if (MYSQLparse((void *)thd) || thd->is_fatal_error)
{ {
DBUG_PRINT("error", ("error during compile or thd->is_fatal_error=%d", DBUG_PRINT("error", ("error during compile or thd->is_fatal_error=%d",
...@@ -1713,13 +1699,10 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root) ...@@ -1713,13 +1699,10 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root)
*/ */
sql_print_error("error during compile of %s.%s or thd->is_fatal_error=%d", sql_print_error("error during compile of %s.%s or thd->is_fatal_error=%d",
dbname.str, name.str, thd->is_fatal_error); dbname.str, name.str, thd->is_fatal_error);
if (lex.sphead)
{ lex.unit.cleanup();
if (&lex != thd->lex)
thd->lex->sphead->restore_lex(thd);
delete lex.sphead; delete lex.sphead;
lex.sphead= 0; sphead= lex.sphead= NULL;
}
ret= EVEX_COMPILE_ERROR; ret= EVEX_COMPILE_ERROR;
goto done; goto done;
} }
...@@ -1734,7 +1717,7 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root) ...@@ -1734,7 +1717,7 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root)
done: done:
lex_end(&lex); lex_end(&lex);
thd->restore_security_context(save_ctx); thd->restore_security_context(&save_ctx);
DBUG_PRINT("note", ("return old data on its place. set back NAMES")); DBUG_PRINT("note", ("return old data on its place. set back NAMES"));
thd->lex= old_lex; thd->lex= old_lex;
...@@ -1772,20 +1755,17 @@ done: ...@@ -1772,20 +1755,17 @@ done:
int int
Event_job_data::execute(THD *thd) Event_job_data::execute(THD *thd)
{ {
Security_context *save_ctx; Security_context save_ctx;
/* this one is local and not needed after exec */ /* this one is local and not needed after exec */
Security_context security_ctx;
int ret= 0; int ret= 0;
DBUG_ENTER("Event_job_data::execute"); DBUG_ENTER("Event_job_data::execute");
DBUG_PRINT("info", ("EXECUTING %s.%s", dbname.str, name.str)); DBUG_PRINT("info", ("EXECUTING %s.%s", dbname.str, name.str));
if ((ret= compile(thd, NULL))) if ((ret= compile(thd, NULL)))
goto done; goto done;
thd->change_security_context(definer_user, definer_host, dbname, thd->change_security_context(definer_user, definer_host, dbname, &save_ctx);
&security_ctx, &save_ctx);
/* /*
THD::~THD will clean this or if there is DROP DATABASE in the SP then THD::~THD will clean this or if there is DROP DATABASE in the SP then
it will be free there. It should not point to our buffer which is allocated it will be free there. It should not point to our buffer which is allocated
...@@ -1810,9 +1790,10 @@ Event_job_data::execute(THD *thd) ...@@ -1810,9 +1790,10 @@ Event_job_data::execute(THD *thd)
ret= -99; ret= -99;
} }
thd->restore_security_context(save_ctx); thd->restore_security_context(&save_ctx);
done: done:
free_sp(); thd->end_statement();
thd->cleanup_after_query();
DBUG_PRINT("info", ("EXECUTED %s.%s ret=%d", dbname.str, name.str, ret)); DBUG_PRINT("info", ("EXECUTED %s.%s ret=%d", dbname.str, name.str, ret));
......
...@@ -178,15 +178,12 @@ public: ...@@ -178,15 +178,12 @@ public:
int int
execute(THD *thd); execute(THD *thd);
private:
int
get_fake_create_event(THD *thd, String *buf);
int int
compile(THD *thd, MEM_ROOT *mem_root); compile(THD *thd, MEM_ROOT *mem_root);
private:
void int
free_sp(); get_fake_create_event(THD *thd, String *buf);
Event_job_data(const Event_job_data &); /* Prevent use of these */ Event_job_data(const Event_job_data &); /* Prevent use of these */
void operator=(Event_job_data &); void operator=(Event_job_data &);
......
...@@ -35,6 +35,14 @@ ...@@ -35,6 +35,14 @@
#define LOCK_QUEUE_DATA() lock_data(SCHED_FUNC, __LINE__) #define LOCK_QUEUE_DATA() lock_data(SCHED_FUNC, __LINE__)
#define UNLOCK_QUEUE_DATA() unlock_data(SCHED_FUNC, __LINE__) #define UNLOCK_QUEUE_DATA() unlock_data(SCHED_FUNC, __LINE__)
struct event_queue_param
{
THD *thd;
Event_queue *queue;
pthread_mutex_t LOCK_loaded;
pthread_cond_t COND_loaded;
};
/* /*
Compares the execute_at members of two Event_queue_element instances. Compares the execute_at members of two Event_queue_element instances.
...@@ -64,6 +72,31 @@ event_queue_element_compare_q(void *vptr, byte* a, byte *b) ...@@ -64,6 +72,31 @@ event_queue_element_compare_q(void *vptr, byte* a, byte *b)
} }
pthread_handler_t
event_queue_loader_thread(void *arg)
{
/* needs to be first for thread_stack */
THD *thd= (THD *)((struct event_queue_param *) arg)->thd;
struct event_queue_param *param= (struct event_queue_param *) arg;
thd->thread_stack= (char *) &thd;
if (post_init_event_thread(thd))
goto end;
DBUG_ENTER("event_queue_loader_thread");
pthread_mutex_lock(&param->LOCK_loaded);
param->queue->load_events_from_db(thd);
pthread_cond_signal(&param->COND_loaded);
pthread_mutex_unlock(&param->LOCK_loaded);
end:
deinit_event_thread(thd);
DBUG_RETURN(0); // Against gcc warnings
}
/* /*
Constructor of class Event_queue. Constructor of class Event_queue.
...@@ -80,6 +113,8 @@ Event_queue::Event_queue() ...@@ -80,6 +113,8 @@ Event_queue::Event_queue()
mutex_last_attempted_lock_in_func= ""; mutex_last_attempted_lock_in_func= "";
mutex_queue_data_locked= mutex_queue_data_attempting_lock= FALSE; mutex_queue_data_locked= mutex_queue_data_attempting_lock= FALSE;
queue_loaded= FALSE;
} }
...@@ -125,8 +160,11 @@ Event_queue::deinit_mutexes() ...@@ -125,8 +160,11 @@ Event_queue::deinit_mutexes()
bool bool
Event_queue::init_queue(Event_db_repository *db_repo, Event_scheduler *sched) Event_queue::init_queue(Event_db_repository *db_repo, Event_scheduler *sched)
{ {
int i= 0; THD *new_thd;
bool ret= FALSE; pthread_t th;
bool res;
struct event_queue_param *event_queue_param_value= NULL;
DBUG_ENTER("Event_queue::init_queue"); DBUG_ENTER("Event_queue::init_queue");
DBUG_PRINT("enter", ("this=0x%lx", this)); DBUG_PRINT("enter", ("this=0x%lx", this));
...@@ -139,8 +177,7 @@ Event_queue::init_queue(Event_db_repository *db_repo, Event_scheduler *sched) ...@@ -139,8 +177,7 @@ Event_queue::init_queue(Event_db_repository *db_repo, Event_scheduler *sched)
NULL, EVENT_QUEUE_EXTENT)) NULL, EVENT_QUEUE_EXTENT))
{ {
sql_print_error("SCHEDULER: Can't initialize the execution queue"); sql_print_error("SCHEDULER: Can't initialize the execution queue");
ret= TRUE; goto err;
goto end;
} }
if (sizeof(my_time_t) != sizeof(time_t)) if (sizeof(my_time_t) != sizeof(time_t))
...@@ -148,13 +185,43 @@ Event_queue::init_queue(Event_db_repository *db_repo, Event_scheduler *sched) ...@@ -148,13 +185,43 @@ Event_queue::init_queue(Event_db_repository *db_repo, Event_scheduler *sched)
sql_print_error("SCHEDULER: sizeof(my_time_t) != sizeof(time_t) ." sql_print_error("SCHEDULER: sizeof(my_time_t) != sizeof(time_t) ."
"The scheduler may not work correctly. Stopping."); "The scheduler may not work correctly. Stopping.");
DBUG_ASSERT(0); DBUG_ASSERT(0);
ret= TRUE; goto err;
goto end;
} }
end: if (!(new_thd= new THD))
goto err;
pre_init_event_thread(new_thd);
event_queue_param_value= (struct event_queue_param *)
my_malloc(sizeof(struct event_queue_param), MYF(0));
event_queue_param_value->thd= new_thd;
event_queue_param_value->queue= this;
pthread_mutex_init(&event_queue_param_value->LOCK_loaded, MY_MUTEX_INIT_FAST);
pthread_cond_init(&event_queue_param_value->COND_loaded, NULL);
pthread_mutex_lock(&event_queue_param_value->LOCK_loaded);
DBUG_PRINT("info", ("Forking new thread for scheduduler. THD=0x%lx", new_thd));
if (!(res= pthread_create(&th, &connection_attrib, event_queue_loader_thread,
(void*)event_queue_param_value)))
{
do {
pthread_cond_wait(&event_queue_param_value->COND_loaded,
&event_queue_param_value->LOCK_loaded);
} while (queue_loaded == FALSE);
}
pthread_mutex_unlock(&event_queue_param_value->LOCK_loaded);
pthread_mutex_destroy(&event_queue_param_value->LOCK_loaded);
pthread_cond_destroy(&event_queue_param_value->COND_loaded);
my_free((char *)event_queue_param_value, MYF(0));
UNLOCK_QUEUE_DATA(); UNLOCK_QUEUE_DATA();
DBUG_RETURN(ret); DBUG_RETURN(res);
err:
UNLOCK_QUEUE_DATA();
DBUG_RETURN(TRUE);
} }
...@@ -498,7 +565,7 @@ Event_queue::load_events_from_db(THD *thd) ...@@ -498,7 +565,7 @@ Event_queue::load_events_from_db(THD *thd)
READ_RECORD read_record_info; READ_RECORD read_record_info;
int ret= -1; int ret= -1;
uint count= 0; uint count= 0;
bool clean_the_queue= FALSE; bool clean_the_queue= TRUE;
/* Compile the events on this root but only for syntax check, then discard */ /* Compile the events on this root but only for syntax check, then discard */
MEM_ROOT boot_root; MEM_ROOT boot_root;
...@@ -518,14 +585,12 @@ Event_queue::load_events_from_db(THD *thd) ...@@ -518,14 +585,12 @@ Event_queue::load_events_from_db(THD *thd)
if (!(et= new Event_queue_element)) if (!(et= new Event_queue_element))
{ {
DBUG_PRINT("info", ("Out of memory")); DBUG_PRINT("info", ("Out of memory"));
clean_the_queue= TRUE;
break; break;
} }
DBUG_PRINT("info", ("Loading event from row.")); DBUG_PRINT("info", ("Loading event from row."));
if ((ret= et->load_from_row(table))) if ((ret= et->load_from_row(table)))
{ {
clean_the_queue= TRUE;
sql_print_error("SCHEDULER: Error while loading from mysql.event. " sql_print_error("SCHEDULER: Error while loading from mysql.event. "
"Table probably corrupted"); "Table probably corrupted");
break; break;
...@@ -536,40 +601,48 @@ Event_queue::load_events_from_db(THD *thd) ...@@ -536,40 +601,48 @@ Event_queue::load_events_from_db(THD *thd)
delete et; delete et;
continue; continue;
} }
#if 0
init_alloc_root(&boot_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC); /* let's find when to be executed */
if (et->compute_next_execution_time())
{
sql_print_error("SCHEDULER: Error while computing execution time of %s.%s."
" Skipping", et->dbname.str, et->name.str);
continue;
}
{
Event_job_data temp_job_data;
DBUG_PRINT("info", ("Event %s loaded from row. ", et->name.str)); DBUG_PRINT("info", ("Event %s loaded from row. ", et->name.str));
temp_job_data.load_from_row(table);
/* We load only on scheduler root just to check whether the body compiles */ /* We load only on scheduler root just to check whether the body compiles */
switch (ret= et->compile(thd, &boot_root)) { switch (ret= temp_job_data.compile(thd, thd->mem_root)) {
case EVEX_MICROSECOND_UNSUP: case EVEX_MICROSECOND_UNSUP:
et->free_sp();
sql_print_error("SCHEDULER: mysql.event is tampered. MICROSECOND is not " sql_print_error("SCHEDULER: mysql.event is tampered. MICROSECOND is not "
"supported but found in mysql.event"); "supported but found in mysql.event");
goto end; break;
case EVEX_COMPILE_ERROR: case EVEX_COMPILE_ERROR:
sql_print_error("SCHEDULER: Error while compiling %s.%s. Aborting load.", sql_print_error("SCHEDULER: Error while compiling %s.%s. Aborting load.",
et->dbname.str, et->name.str); et->dbname.str, et->name.str);
goto end; break;
default: default:
/* Free it, it will be compiled again on the worker thread */
et->free_sp();
break; break;
} }
free_root(&boot_root, MYF(0)); thd->end_statement();
thd->cleanup_after_query();
/* let's find when to be executed */ }
if (et->compute_next_execution_time()) if (ret)
{ {
sql_print_error("SCHEDULER: Error while computing execution time of %s.%s." delete et;
" Skipping", et->dbname.str, et->name.str); goto end;
continue;
} }
#endif
DBUG_PRINT("load_events_from_db", ("Adding 0x%lx to the exec list.")); DBUG_PRINT("load_events_from_db", ("Adding 0x%lx to the exec list."));
queue_insert_safe(&queue, (byte *) et); queue_insert_safe(&queue, (byte *) et);
count++; count++;
} }
clean_the_queue= FALSE;
end: end:
end_read_record(&read_record_info); end_read_record(&read_record_info);
...@@ -589,6 +662,8 @@ end: ...@@ -589,6 +662,8 @@ end:
close_thread_tables(thd); close_thread_tables(thd);
queue_loaded= TRUE;
DBUG_PRINT("info", ("Status code %d. Loaded %d event(s)", ret, count)); DBUG_PRINT("info", ("Status code %d. Loaded %d event(s)", ret, count));
DBUG_RETURN(ret); DBUG_RETURN(ret);
} }
...@@ -713,6 +788,7 @@ Event_queue::empty_queue() ...@@ -713,6 +788,7 @@ Event_queue::empty_queue()
uint i; uint i;
DBUG_ENTER("Event_queue::empty_queue"); DBUG_ENTER("Event_queue::empty_queue");
DBUG_PRINT("enter", ("Purging the queue. %d element(s)", queue.elements)); DBUG_PRINT("enter", ("Purging the queue. %d element(s)", queue.elements));
sql_print_information("SCHEDULER: Purging queue. %u events", queue.elements);
/* empty the queue */ /* empty the queue */
for (i= 0; i < queue.elements; ++i) for (i= 0; i < queue.elements; ++i)
{ {
......
...@@ -68,12 +68,13 @@ public: ...@@ -68,12 +68,13 @@ public:
bool bool
dump_internal_status(THD *thd); dump_internal_status(THD *thd);
int
load_events_from_db(THD *thd);
protected: protected:
Event_queue_element * Event_queue_element *
find_n_remove_event(LEX_STRING db, LEX_STRING name); find_n_remove_event(LEX_STRING db, LEX_STRING name);
int
load_events_from_db(THD *thd);
void void
drop_matching_events(THD *thd, LEX_STRING pattern, drop_matching_events(THD *thd, LEX_STRING pattern,
...@@ -82,11 +83,24 @@ protected: ...@@ -82,11 +83,24 @@ protected:
void void
empty_queue(); empty_queue();
void
notify_observers();
void
dbug_dump_queue(time_t now);
/* LOCK_event_queue is the mutex which protects the access to the queue. */ /* LOCK_event_queue is the mutex which protects the access to the queue. */
pthread_mutex_t LOCK_event_queue; pthread_mutex_t LOCK_event_queue;
Event_db_repository *db_repository; Event_db_repository *db_repository;
Event_scheduler *scheduler;
/* The sorted queue with the Event_job_data objects */
QUEUE queue;
bool queue_loaded;
uint mutex_last_locked_at_line; uint mutex_last_locked_at_line;
uint mutex_last_unlocked_at_line; uint mutex_last_unlocked_at_line;
uint mutex_last_attempted_lock_at_line; uint mutex_last_attempted_lock_at_line;
...@@ -102,17 +116,6 @@ protected: ...@@ -102,17 +116,6 @@ protected:
void void
unlock_data(const char *func, uint line); unlock_data(const char *func, uint line);
void
notify_observers();
void
dbug_dump_queue(time_t now);
Event_scheduler *scheduler;
/* The sorted queue with the Event_job_data objects */
QUEUE queue;
}; };
#endif /* _EVENT_QUEUE_H_ */ #endif /* _EVENT_QUEUE_H_ */
...@@ -40,9 +40,6 @@ struct scheduler_param ...@@ -40,9 +40,6 @@ struct scheduler_param
Event_scheduler *scheduler; Event_scheduler *scheduler;
}; };
struct scheduler_param scheduler_param_value;
static static
LEX_STRING scheduler_states_names[] = LEX_STRING scheduler_states_names[] =
...@@ -103,25 +100,23 @@ evex_print_warnings(THD *thd, Event_job_data *et) ...@@ -103,25 +100,23 @@ evex_print_warnings(THD *thd, Event_job_data *et)
/* /*
Inits an scheduler thread handler, both the main and a worker Performs pre- pthread_create() initialisation of THD. Do this
in the thread that will pass THD to the child thread. In the
child thread call post_init_event_thread().
SYNOPSIS SYNOPSIS
init_event_thread() pre_init_event_thread()
thd - the THD of the thread. Has to be allocated by the caller. thd The THD of the thread. Has to be allocated by the caller.
NOTES NOTES
1. The host of the thead is my_localhost 1. The host of the thead is my_localhost
2. thd->net is initted with NULL - no communication. 2. thd->net is initted with NULL - no communication.
RETURN VALUE
0 OK
-1 Error
*/ */
static int void
init_scheduler_thread(THD* thd) pre_init_event_thread(THD* thd)
{ {
DBUG_ENTER("init_event_thread"); DBUG_ENTER("pre_init_event_thread");
thd->client_capabilities= 0; thd->client_capabilities= 0;
thd->security_ctx->master_access= 0; thd->security_ctx->master_access= 0;
thd->security_ctx->db_access= 0; thd->security_ctx->db_access= 0;
...@@ -148,7 +143,36 @@ init_scheduler_thread(THD* thd) ...@@ -148,7 +143,36 @@ init_scheduler_thread(THD* thd)
thd->version= refresh_version; thd->version= refresh_version;
thd->set_time(); thd->set_time();
DBUG_RETURN(0); DBUG_VOID_RETURN;
}
/*
Performs post initialization of structures in a new thread.
SYNOPSIS
post_init_event_thread()
thd Thread
*/
bool
post_init_event_thread(THD *thd)
{
my_thread_init();
pthread_detach_this_thread();
thd->real_id= pthread_self();
if (init_thr_lock() || thd->store_globals())
{
thd->cleanup();
return TRUE;
}
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
sigset_t set;
VOID(sigemptyset(&set)); // Get mask in use
VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
#endif
return FALSE;
} }
...@@ -160,7 +184,7 @@ init_scheduler_thread(THD* thd) ...@@ -160,7 +184,7 @@ init_scheduler_thread(THD* thd)
thd Thread thd Thread
*/ */
static void void
deinit_event_thread(THD *thd) deinit_event_thread(THD *thd)
{ {
thd->proc_info= "Clearing"; thd->proc_info= "Clearing";
...@@ -192,29 +216,18 @@ pthread_handler_t ...@@ -192,29 +216,18 @@ pthread_handler_t
event_scheduler_thread(void *arg) event_scheduler_thread(void *arg)
{ {
/* needs to be first for thread_stack */ /* needs to be first for thread_stack */
THD *thd= (THD *)(*(struct scheduler_param *) arg).thd; THD *thd= (THD *)((struct scheduler_param *) arg)->thd;
Event_scheduler *scheduler= ((struct scheduler_param *) arg)->scheduler;
thd->thread_stack= (char *)&thd; // remember where our stack is my_free((char*)arg, MYF(0));
DBUG_ENTER("event_scheduler_thread");
my_thread_init(); thd->thread_stack= (char *)&thd; // remember where our stack is
pthread_detach_this_thread();
thd->real_id=pthread_self();
if (init_thr_lock() || thd->store_globals())
{
thd->cleanup();
goto end;
}
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__) DBUG_ENTER("event_scheduler_thread");
sigset_t set;
VOID(sigemptyset(&set)); // Get mask in use
VOID(pthread_sigmask(SIG_UNBLOCK,&set,&thd->block_signals));
#endif
((struct scheduler_param *) arg)->scheduler->run(thd); if (!post_init_event_thread(thd))
scheduler->run(thd);
end:
deinit_event_thread(thd); deinit_event_thread(thd);
DBUG_RETURN(0); // Against gcc warnings DBUG_RETURN(0); // Against gcc warnings
...@@ -242,27 +255,13 @@ event_worker_thread(void *arg) ...@@ -242,27 +255,13 @@ event_worker_thread(void *arg)
int ret; int ret;
thd= event->thd; thd= event->thd;
thd->thread_stack= (char *) &thd;
thd->thread_stack= (char *) &thd; // remember where our stack is
DBUG_ENTER("event_worker_thread");
my_thread_init(); if (post_init_event_thread(thd))
pthread_detach_this_thread();
thd->real_id=pthread_self();
if (init_thr_lock() || thd->store_globals())
{
thd->cleanup();
goto end; goto end;
}
#if !defined(__WIN__) && !defined(OS2) && !defined(__NETWARE__)
sigset_t set;
VOID(sigemptyset(&set)); // Get mask in use
VOID(pthread_sigmask(SIG_UNBLOCK, &set, &thd->block_signals));
#endif
thd->init_for_queries();
DBUG_ENTER("event_worker_thread");
DBUG_PRINT("info", ("Baikonur, time is %d, BURAN reporting and operational." DBUG_PRINT("info", ("Baikonur, time is %d, BURAN reporting and operational."
"THD=0x%lx", time(NULL), thd)); "THD=0x%lx", time(NULL), thd));
...@@ -375,6 +374,7 @@ Event_scheduler::start() ...@@ -375,6 +374,7 @@ Event_scheduler::start()
THD *new_thd= NULL; THD *new_thd= NULL;
bool ret= FALSE; bool ret= FALSE;
pthread_t th; pthread_t th;
struct scheduler_param *scheduler_param_value;
DBUG_ENTER("Event_scheduler::start"); DBUG_ENTER("Event_scheduler::start");
LOCK_SCHEDULER_DATA(); LOCK_SCHEDULER_DATA();
...@@ -382,21 +382,24 @@ Event_scheduler::start() ...@@ -382,21 +382,24 @@ Event_scheduler::start()
if (state > INITIALIZED) if (state > INITIALIZED)
goto end; goto end;
if (!(new_thd= new THD) || init_scheduler_thread(new_thd)) if (!(new_thd= new THD))
{ {
sql_print_error("SCHEDULER: Cannot init manager event thread."); sql_print_error("SCHEDULER: Cannot init manager event thread.");
ret= TRUE; ret= TRUE;
goto end; goto end;
} }
pre_init_event_thread(new_thd);
new_thd->system_thread= SYSTEM_THREAD_EVENT_SCHEDULER; new_thd->system_thread= SYSTEM_THREAD_EVENT_SCHEDULER;
new_thd->command= COM_DAEMON; new_thd->command= COM_DAEMON;
scheduler_param_value.thd= new_thd; scheduler_param_value=
scheduler_param_value.scheduler= this; (struct scheduler_param *)my_malloc(sizeof(struct scheduler_param), MYF(0));
scheduler_param_value->thd= new_thd;
scheduler_param_value->scheduler= this;
DBUG_PRINT("info", ("Forking new thread for scheduduler. THD=0x%lx", new_thd)); DBUG_PRINT("info", ("Forking new thread for scheduduler. THD=0x%lx", new_thd));
if (pthread_create(&th, &connection_attrib, event_scheduler_thread, if (pthread_create(&th, &connection_attrib, event_scheduler_thread,
(void*)&scheduler_param_value)) (void*)scheduler_param_value))
{ {
DBUG_PRINT("error", ("cannot create a new thread")); DBUG_PRINT("error", ("cannot create a new thread"));
state= INITIALIZED; state= INITIALIZED;
...@@ -588,9 +591,10 @@ Event_scheduler::execute_top(THD *thd, Event_job_data *job_data) ...@@ -588,9 +591,10 @@ Event_scheduler::execute_top(THD *thd, Event_job_data *job_data)
pthread_t th; pthread_t th;
int res= 0; int res= 0;
DBUG_ENTER("Event_scheduler::execute_top"); DBUG_ENTER("Event_scheduler::execute_top");
if (!(new_thd= new THD) || init_scheduler_thread(new_thd)) if (!(new_thd= new THD))
goto error; goto error;
pre_init_event_thread(new_thd);
new_thd->system_thread= SYSTEM_THREAD_EVENT_WORKER; new_thd->system_thread= SYSTEM_THREAD_EVENT_WORKER;
job_data->thd= new_thd; job_data->thd= new_thd;
DBUG_PRINT("info", ("BURAN %s@%s ready for start t-3..2..1..0..ignition", DBUG_PRINT("info", ("BURAN %s@%s ready for start t-3..2..1..0..ignition",
......
...@@ -19,6 +19,15 @@ ...@@ -19,6 +19,15 @@
class Event_queue; class Event_queue;
class Event_job_data; class Event_job_data;
void
pre_init_event_thread(THD* thd);
bool
post_init_event_thread(THD* thd);
void
deinit_event_thread(THD *thd);
class Event_scheduler class Event_scheduler
{ {
public: public:
......
...@@ -556,11 +556,16 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */) ...@@ -556,11 +556,16 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
1 Error in case the scheduler can't start 1 Error in case the scheduler can't start
*/ */
int bool
Events::init() Events::init()
{ {
int res;
DBUG_ENTER("Events::init"); DBUG_ENTER("Events::init");
event_queue->init_queue(db_repository, scheduler); if (event_queue->init_queue(db_repository, scheduler))
{
sql_print_information("SCHEDULER: Error while loading from disk.");
DBUG_RETURN(TRUE);
}
scheduler->init_scheduler(event_queue); scheduler->init_scheduler(event_queue);
/* it should be an assignment! */ /* it should be an assignment! */
...@@ -571,7 +576,7 @@ Events::init() ...@@ -571,7 +576,7 @@ Events::init()
DBUG_RETURN(scheduler->start()); DBUG_RETURN(scheduler->start());
} }
DBUG_RETURN(0); DBUG_RETURN(FALSE);
} }
......
...@@ -52,7 +52,7 @@ public: ...@@ -52,7 +52,7 @@ public:
static ulong opt_event_scheduler; static ulong opt_event_scheduler;
static TYPELIB opt_typelib; static TYPELIB opt_typelib;
int bool
init(); init();
void void
......
...@@ -3675,7 +3675,8 @@ we force server id to 2, but this MySQL server will not act as a slave."); ...@@ -3675,7 +3675,8 @@ we force server id to 2, but this MySQL server will not act as a slave.");
if (!opt_noacl) if (!opt_noacl)
{ {
Events::get_instance()->init(); if (Events::get_instance()->init())
unireg_abort(1);
} }
#if defined(__NT__) || defined(HAVE_SMEM) #if defined(__NT__) || defined(HAVE_SMEM)
handle_connections_methods(); handle_connections_methods();
......
...@@ -640,10 +640,12 @@ sp_head::create(THD *thd) ...@@ -640,10 +640,12 @@ sp_head::create(THD *thd)
sp_head::~sp_head() sp_head::~sp_head()
{ {
DBUG_ENTER("sp_head::~sp_head");
destroy(); destroy();
delete m_next_cached_sp; delete m_next_cached_sp;
if (m_thd) if (m_thd)
restore_thd_mem_root(m_thd); restore_thd_mem_root(m_thd);
DBUG_VOID_RETURN;
} }
void void
......
...@@ -2085,21 +2085,20 @@ bool Security_context::set_user(char *user_arg) ...@@ -2085,21 +2085,20 @@ bool Security_context::set_user(char *user_arg)
bool bool
THD::change_security_context(LEX_STRING user, LEX_STRING host, THD::change_security_context(LEX_STRING user, LEX_STRING host,
LEX_STRING db, Security_context *s_ctx, LEX_STRING db, Security_context *backup)
Security_context **backup)
{ {
DBUG_ENTER("change_security_context"); DBUG_ENTER("change_security_context");
DBUG_PRINT("info",("%s@%s@%s", user.str, host.str, db.str)); DBUG_PRINT("info",("%s@%s@%s", user.str, host.str, db.str));
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
s_ctx->init();
*backup= 0; *backup= main_security_ctx;
if (acl_getroot_no_password(s_ctx, user.str, host.str, host.str, db.str)) if (acl_getroot_no_password(&main_security_ctx, user.str, host.str, host.str,
db.str))
{ {
my_error(ER_NO_SUCH_USER, MYF(0), user.str, host.str); my_error(ER_NO_SUCH_USER, MYF(0), user.str, host.str);
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
*backup= security_ctx; security_ctx= &main_security_ctx;
security_ctx= s_ctx;
#endif #endif
DBUG_RETURN(FALSE); DBUG_RETURN(FALSE);
} }
...@@ -2119,7 +2118,10 @@ THD::restore_security_context(Security_context *backup) ...@@ -2119,7 +2118,10 @@ THD::restore_security_context(Security_context *backup)
DBUG_ENTER("restore_security_context"); DBUG_ENTER("restore_security_context");
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (backup) if (backup)
security_ctx= backup; {
main_security_ctx= *backup;
security_ctx= &main_security_ctx;
}
#endif #endif
DBUG_VOID_RETURN; DBUG_VOID_RETURN;
} }
......
...@@ -871,8 +871,7 @@ public: ...@@ -871,8 +871,7 @@ public:
bool bool
change_security_context(LEX_STRING user, LEX_STRING host, change_security_context(LEX_STRING user, LEX_STRING host,
LEX_STRING db, Security_context *s_ctx, LEX_STRING db, Security_context *backup);
Security_context **backup);
void void
restore_security_context(Security_context *backup); restore_security_context(Security_context *backup);
......
...@@ -171,6 +171,7 @@ void lex_start(THD *thd, const uchar *buf, uint length) ...@@ -171,6 +171,7 @@ void lex_start(THD *thd, const uchar *buf, uint length)
lex->sql_command= SQLCOM_END; lex->sql_command= SQLCOM_END;
lex->duplicates= DUP_ERROR; lex->duplicates= DUP_ERROR;
lex->ignore= 0; lex->ignore= 0;
lex->spname= NULL;
lex->sphead= NULL; lex->sphead= NULL;
lex->spcont= NULL; lex->spcont= NULL;
lex->proc_list.first= 0; lex->proc_list.first= 0;
......
...@@ -4652,6 +4652,13 @@ alter: ...@@ -4652,6 +4652,13 @@ alter:
YYTHD->client_capabilities is set back to original value YYTHD->client_capabilities is set back to original value
*/ */
{ {
/*
It is safe to use Lex->spname because
ALTER EVENT xxx RENATE TO yyy DO ALTER EVENT RENAME TO
is not allowed. Lex->spname is used in the case of RENAME TO
If it had to be supported spname had to be added to
Event_parse_data.
*/
Lex->spname= NULL; Lex->spname= NULL;
if (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD))) if (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment