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()
*/
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():
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)
}
/*
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
sp_head object held by the event
......@@ -1651,9 +1640,7 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root)
CHARSET_INFO *old_character_set_client,
*old_collation_connection,
*old_character_set_results;
Security_context *save_ctx;
/* this one is local and not needed after exec */
Security_context security_ctx;
Security_context save_ctx;
DBUG_ENTER("Event_job_data::compile");
......@@ -1699,10 +1686,9 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root)
thd->query_length= show_create.length();
DBUG_PRINT("info", ("query:%s",thd->query));
thd->change_security_context(definer_user, definer_host, dbname,
&security_ctx, &save_ctx);
thd->change_security_context(definer_user, definer_host, dbname, &save_ctx);
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)
{
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)
*/
sql_print_error("error during compile of %s.%s or thd->is_fatal_error=%d",
dbname.str, name.str, thd->is_fatal_error);
if (lex.sphead)
{
if (&lex != thd->lex)
thd->lex->sphead->restore_lex(thd);
delete lex.sphead;
lex.sphead= 0;
}
lex.unit.cleanup();
delete lex.sphead;
sphead= lex.sphead= NULL;
ret= EVEX_COMPILE_ERROR;
goto done;
}
......@@ -1734,7 +1717,7 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root)
done:
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"));
thd->lex= old_lex;
......@@ -1772,20 +1755,17 @@ done:
int
Event_job_data::execute(THD *thd)
{
Security_context *save_ctx;
Security_context save_ctx;
/* this one is local and not needed after exec */
Security_context security_ctx;
int ret= 0;
DBUG_ENTER("Event_job_data::execute");
DBUG_PRINT("info", ("EXECUTING %s.%s", dbname.str, name.str));
if ((ret= compile(thd, NULL)))
goto done;
thd->change_security_context(definer_user, definer_host, dbname,
&security_ctx, &save_ctx);
thd->change_security_context(definer_user, definer_host, dbname, &save_ctx);
/*
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
......@@ -1810,9 +1790,10 @@ Event_job_data::execute(THD *thd)
ret= -99;
}
thd->restore_security_context(save_ctx);
thd->restore_security_context(&save_ctx);
done:
free_sp();
thd->end_statement();
thd->cleanup_after_query();
DBUG_PRINT("info", ("EXECUTED %s.%s ret=%d", dbname.str, name.str, ret));
......
......@@ -178,15 +178,12 @@ public:
int
execute(THD *thd);
private:
int
get_fake_create_event(THD *thd, String *buf);
int
compile(THD *thd, MEM_ROOT *mem_root);
void
free_sp();
private:
int
get_fake_create_event(THD *thd, String *buf);
Event_job_data(const Event_job_data &); /* Prevent use of these */
void operator=(Event_job_data &);
......
......@@ -35,6 +35,14 @@
#define LOCK_QUEUE_DATA() lock_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.
......@@ -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.
......@@ -80,6 +113,8 @@ Event_queue::Event_queue()
mutex_last_attempted_lock_in_func= "";
mutex_queue_data_locked= mutex_queue_data_attempting_lock= FALSE;
queue_loaded= FALSE;
}
......@@ -125,8 +160,11 @@ Event_queue::deinit_mutexes()
bool
Event_queue::init_queue(Event_db_repository *db_repo, Event_scheduler *sched)
{
int i= 0;
bool ret= FALSE;
THD *new_thd;
pthread_t th;
bool res;
struct event_queue_param *event_queue_param_value= NULL;
DBUG_ENTER("Event_queue::init_queue");
DBUG_PRINT("enter", ("this=0x%lx", this));
......@@ -139,8 +177,7 @@ Event_queue::init_queue(Event_db_repository *db_repo, Event_scheduler *sched)
NULL, EVENT_QUEUE_EXTENT))
{
sql_print_error("SCHEDULER: Can't initialize the execution queue");
ret= TRUE;
goto end;
goto err;
}
if (sizeof(my_time_t) != sizeof(time_t))
......@@ -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) ."
"The scheduler may not work correctly. Stopping.");
DBUG_ASSERT(0);
ret= TRUE;
goto end;
goto err;
}
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();
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)
READ_RECORD read_record_info;
int ret= -1;
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 */
MEM_ROOT boot_root;
......@@ -518,14 +585,12 @@ Event_queue::load_events_from_db(THD *thd)
if (!(et= new Event_queue_element))
{
DBUG_PRINT("info", ("Out of memory"));
clean_the_queue= TRUE;
break;
}
DBUG_PRINT("info", ("Loading event from row."));
if ((ret= et->load_from_row(table)))
{
clean_the_queue= TRUE;
sql_print_error("SCHEDULER: Error while loading from mysql.event. "
"Table probably corrupted");
break;
......@@ -536,27 +601,6 @@ Event_queue::load_events_from_db(THD *thd)
delete et;
continue;
}
#if 0
init_alloc_root(&boot_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
DBUG_PRINT("info", ("Event %s loaded from row. ", et->name.str));
/* We load only on scheduler root just to check whether the body compiles */
switch (ret= et->compile(thd, &boot_root)) {
case EVEX_MICROSECOND_UNSUP:
et->free_sp();
sql_print_error("SCHEDULER: mysql.event is tampered. MICROSECOND is not "
"supported but found in mysql.event");
goto end;
case EVEX_COMPILE_ERROR:
sql_print_error("SCHEDULER: Error while compiling %s.%s. Aborting load.",
et->dbname.str, et->name.str);
goto end;
default:
/* Free it, it will be compiled again on the worker thread */
et->free_sp();
break;
}
free_root(&boot_root, MYF(0));
/* let's find when to be executed */
if (et->compute_next_execution_time())
......@@ -565,11 +609,40 @@ Event_queue::load_events_from_db(THD *thd)
" Skipping", et->dbname.str, et->name.str);
continue;
}
#endif
{
Event_job_data temp_job_data;
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 */
switch (ret= temp_job_data.compile(thd, thd->mem_root)) {
case EVEX_MICROSECOND_UNSUP:
sql_print_error("SCHEDULER: mysql.event is tampered. MICROSECOND is not "
"supported but found in mysql.event");
break;
case EVEX_COMPILE_ERROR:
sql_print_error("SCHEDULER: Error while compiling %s.%s. Aborting load.",
et->dbname.str, et->name.str);
break;
default:
break;
}
thd->end_statement();
thd->cleanup_after_query();
}
if (ret)
{
delete et;
goto end;
}
DBUG_PRINT("load_events_from_db", ("Adding 0x%lx to the exec list."));
queue_insert_safe(&queue, (byte *) et);
count++;
}
clean_the_queue= FALSE;
end:
end_read_record(&read_record_info);
......@@ -585,10 +658,12 @@ end:
}
/* Force close to free memory */
thd->version--;
thd->version--;
close_thread_tables(thd);
queue_loaded= TRUE;
DBUG_PRINT("info", ("Status code %d. Loaded %d event(s)", ret, count));
DBUG_RETURN(ret);
}
......@@ -713,6 +788,7 @@ Event_queue::empty_queue()
uint i;
DBUG_ENTER("Event_queue::empty_queue");
DBUG_PRINT("enter", ("Purging the queue. %d element(s)", queue.elements));
sql_print_information("SCHEDULER: Purging queue. %u events", queue.elements);
/* empty the queue */
for (i= 0; i < queue.elements; ++i)
{
......
......@@ -68,12 +68,13 @@ public:
bool
dump_internal_status(THD *thd);
int
load_events_from_db(THD *thd);
protected:
Event_queue_element *
find_n_remove_event(LEX_STRING db, LEX_STRING name);
int
load_events_from_db(THD *thd);
void
drop_matching_events(THD *thd, LEX_STRING pattern,
......@@ -82,11 +83,24 @@ protected:
void
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. */
pthread_mutex_t LOCK_event_queue;
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_unlocked_at_line;
uint mutex_last_attempted_lock_at_line;
......@@ -95,24 +109,13 @@ protected:
const char* mutex_last_attempted_lock_in_func;
bool mutex_queue_data_locked;
bool mutex_queue_data_attempting_lock;
/* helper functions for working with mutexes & conditionals */
void
lock_data(const char *func, uint line);
void
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_ */
......@@ -40,9 +40,6 @@ struct scheduler_param
Event_scheduler *scheduler;
};
struct scheduler_param scheduler_param_value;
static
LEX_STRING scheduler_states_names[] =
......@@ -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
init_event_thread()
thd - the THD of the thread. Has to be allocated by the caller.
pre_init_event_thread()
thd The THD of the thread. Has to be allocated by the caller.
NOTES
1. The host of the thead is my_localhost
2. thd->net is initted with NULL - no communication.
RETURN VALUE
0 OK
-1 Error
*/
static int
init_scheduler_thread(THD* thd)
void
pre_init_event_thread(THD* thd)
{
DBUG_ENTER("init_event_thread");
DBUG_ENTER("pre_init_event_thread");
thd->client_capabilities= 0;
thd->security_ctx->master_access= 0;
thd->security_ctx->db_access= 0;
......@@ -148,7 +143,36 @@ init_scheduler_thread(THD* thd)
thd->version= refresh_version;
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)
thd Thread
*/
static void
void
deinit_event_thread(THD *thd)
{
thd->proc_info= "Clearing";
......@@ -192,29 +216,18 @@ pthread_handler_t
event_scheduler_thread(void *arg)
{
/* 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
DBUG_ENTER("event_scheduler_thread");
my_free((char*)arg, MYF(0));
my_thread_init();
pthread_detach_this_thread();
thd->real_id=pthread_self();
if (init_thr_lock() || thd->store_globals())
{
thd->cleanup();
goto end;
}
thd->thread_stack= (char *)&thd; // remember where our stack is
#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
DBUG_ENTER("event_scheduler_thread");
((struct scheduler_param *) arg)->scheduler->run(thd);
if (!post_init_event_thread(thd))
scheduler->run(thd);
end:
deinit_event_thread(thd);
DBUG_RETURN(0); // Against gcc warnings
......@@ -242,27 +255,13 @@ event_worker_thread(void *arg)
int ret;
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();
pthread_detach_this_thread();
thd->real_id=pthread_self();
if (init_thr_lock() || thd->store_globals())
{
thd->cleanup();
if (post_init_event_thread(thd))
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."
"THD=0x%lx", time(NULL), thd));
......@@ -375,6 +374,7 @@ Event_scheduler::start()
THD *new_thd= NULL;
bool ret= FALSE;
pthread_t th;
struct scheduler_param *scheduler_param_value;
DBUG_ENTER("Event_scheduler::start");
LOCK_SCHEDULER_DATA();
......@@ -382,21 +382,24 @@ Event_scheduler::start()
if (state > INITIALIZED)
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.");
ret= TRUE;
goto end;
}
pre_init_event_thread(new_thd);
new_thd->system_thread= SYSTEM_THREAD_EVENT_SCHEDULER;
new_thd->command= COM_DAEMON;
scheduler_param_value.thd= new_thd;
scheduler_param_value.scheduler= this;
scheduler_param_value=
(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));
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"));
state= INITIALIZED;
......@@ -588,9 +591,10 @@ Event_scheduler::execute_top(THD *thd, Event_job_data *job_data)
pthread_t th;
int res= 0;
DBUG_ENTER("Event_scheduler::execute_top");
if (!(new_thd= new THD) || init_scheduler_thread(new_thd))
if (!(new_thd= new THD))
goto error;
pre_init_event_thread(new_thd);
new_thd->system_thread= SYSTEM_THREAD_EVENT_WORKER;
job_data->thd= new_thd;
DBUG_PRINT("info", ("BURAN %s@%s ready for start t-3..2..1..0..ignition",
......
......@@ -19,6 +19,15 @@
class Event_queue;
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
{
public:
......
......@@ -556,11 +556,16 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
1 Error in case the scheduler can't start
*/
int
bool
Events::init()
{
int res;
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);
/* it should be an assignment! */
......@@ -571,7 +576,7 @@ Events::init()
DBUG_RETURN(scheduler->start());
}
DBUG_RETURN(0);
DBUG_RETURN(FALSE);
}
......
......@@ -52,7 +52,7 @@ public:
static ulong opt_event_scheduler;
static TYPELIB opt_typelib;
int
bool
init();
void
......
......@@ -3675,7 +3675,8 @@ we force server id to 2, but this MySQL server will not act as a slave.");
if (!opt_noacl)
{
Events::get_instance()->init();
if (Events::get_instance()->init())
unireg_abort(1);
}
#if defined(__NT__) || defined(HAVE_SMEM)
handle_connections_methods();
......
......@@ -640,10 +640,12 @@ sp_head::create(THD *thd)
sp_head::~sp_head()
{
DBUG_ENTER("sp_head::~sp_head");
destroy();
delete m_next_cached_sp;
if (m_thd)
restore_thd_mem_root(m_thd);
DBUG_VOID_RETURN;
}
void
......
......@@ -2085,21 +2085,20 @@ bool Security_context::set_user(char *user_arg)
bool
THD::change_security_context(LEX_STRING user, LEX_STRING host,
LEX_STRING db, Security_context *s_ctx,
Security_context **backup)
LEX_STRING db, Security_context *backup)
{
DBUG_ENTER("change_security_context");
DBUG_PRINT("info",("%s@%s@%s", user.str, host.str, db.str));
#ifndef NO_EMBEDDED_ACCESS_CHECKS
s_ctx->init();
*backup= 0;
if (acl_getroot_no_password(s_ctx, user.str, host.str, host.str, db.str))
*backup= main_security_ctx;
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);
DBUG_RETURN(TRUE);
}
*backup= security_ctx;
security_ctx= s_ctx;
security_ctx= &main_security_ctx;
#endif
DBUG_RETURN(FALSE);
}
......@@ -2119,7 +2118,10 @@ THD::restore_security_context(Security_context *backup)
DBUG_ENTER("restore_security_context");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (backup)
security_ctx= backup;
{
main_security_ctx= *backup;
security_ctx= &main_security_ctx;
}
#endif
DBUG_VOID_RETURN;
}
......
......@@ -871,8 +871,7 @@ public:
bool
change_security_context(LEX_STRING user, LEX_STRING host,
LEX_STRING db, Security_context *s_ctx,
Security_context **backup);
LEX_STRING db, Security_context *backup);
void
restore_security_context(Security_context *backup);
......
......@@ -171,6 +171,7 @@ void lex_start(THD *thd, const uchar *buf, uint length)
lex->sql_command= SQLCOM_END;
lex->duplicates= DUP_ERROR;
lex->ignore= 0;
lex->spname= NULL;
lex->sphead= NULL;
lex->spcont= NULL;
lex->proc_list.first= 0;
......
......@@ -4652,6 +4652,13 @@ alter:
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;
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