Commit 3c793e23 authored by andrey@lmy004's avatar andrey@lmy004

WL#3337 (Events new architecture)

This cut No 7 should finish the part of fixing the parsing of the events :
- Event_timed is no more used during parsing. Less problems because it has
  a mutex. Event_parse_data class is used during parsing. It is suited only
  for this purpose. It's pretty lightweight
- Late checking of data from parsing is being performed. This should solve
  the problems of nested events in SP or other events (for the situation 
  of no nested bodies). Before if an ALTER EVENT was in a SP, then when the
  SP was compiled, and not executed, the actual init_xxx methods of Event_timed
  were called, which is wrong.
- It could be a side effect of using a specialized class, but test events_stress is
  now 25% quicker.

Cut No8 will start splitting Event_scheduler into 2 parts, the QUEUE will be moved
to Event_queue.
parent e5e8713c
......@@ -297,9 +297,9 @@ select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_comp
db name body definer convert_tz(execute_at, 'UTC', 'SYSTEM') on_completion
events_test e_26 set @a = 5 root@localhost 2017-01-01 00:00:00 DROP
drop event e_26;
create event e_26 on schedule at NULL disabled do set @a = 5;
create event e_26 on schedule at NULL disable do set @a = 5;
ERROR HY000: Incorrect AT value: 'NULL'
create event e_26 on schedule at 'definitely not a datetime' disabled do set @a = 5;
create event e_26 on schedule at 'definitely not a datetime' disable do set @a = 5;
ERROR HY000: Incorrect AT value: 'definitely not a datetime'
set names utf8;
create event задачка on schedule every 123 minute starts now() ends now() + interval 1 month do select 1;
......
......@@ -255,9 +255,9 @@ create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5;
select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event;
drop event e_26;
--error ER_WRONG_VALUE
create event e_26 on schedule at NULL disabled do set @a = 5;
create event e_26 on schedule at NULL disable do set @a = 5;
--error ER_WRONG_VALUE
create event e_26 on schedule at 'definitely not a datetime' disabled do set @a = 5;
create event e_26 on schedule at 'definitely not a datetime' disable do set @a = 5;
set names utf8;
create event задаÑка on schedule every 123 minute starts now() ends now() + interval 1 month do select 1;
......
......@@ -35,186 +35,18 @@ Event_parse_data::new_instance(THD *thd)
Event_parse_data::Event_parse_data()
{
item_execute_at= item_expression= item_starts= item_ends= NULL;
}
/*
Set body of the event - what should be executed.
SYNOPSIS
Event_timed::init_body()
thd THD
NOTE
The body is extracted by copying all data between the
start of the body set by another method and the current pointer in Lex.
Some questionable removal of characters is done in here, and that part
should be refactored when the parser is smarter.
*/
void
Event_parse_data::init_body(THD *thd)
{
DBUG_ENTER("Event_parse_data::init_body");
DBUG_PRINT("info", ("body=[%s] body_begin=0x%ld end=0x%ld", body_begin,
body_begin, thd->lex->ptr));
body.length= thd->lex->ptr - body_begin;
const uchar *body_end= body_begin + body.length - 1;
/* Trim nuls or close-comments ('*'+'/') or spaces at the end */
while (body_begin < body_end)
{
if ((*body_end == '\0') ||
(my_isspace(thd->variables.character_set_client, *body_end)))
{ /* consume NULs and meaningless whitespace */
--body.length;
--body_end;
continue;
}
/*
consume closing comments
This is arguably wrong, but it's the best we have until the parser is
changed to be smarter. FIXME PARSER
See also the sp_head code, where something like this is done also.
One idea is to keep in the lexer structure the count of the number of
open-comments we've entered, and scan left-to-right looking for a
closing comment IFF the count is greater than zero.
Another idea is to remove the closing comment-characters wholly in the
parser, since that's where it "removes" the opening characters.
*/
if ((*(body_end - 1) == '*') && (*body_end == '/'))
{
DBUG_PRINT("info", ("consumend one '*" "/' comment in the query '%s'",
body_begin));
body.length-= 2;
body_end-= 2;
continue;
}
break; /* none were found, so we have excised all we can. */
}
/* the first is always whitespace which I cannot skip in the parser */
while (my_isspace(thd->variables.character_set_client, *body_begin))
{
++body_begin;
--body.length;
}
body.str= thd->strmake((char *)body_begin, body.length);
DBUG_VOID_RETURN;
}
/*
Constructor
SYNOPSIS
Event_timed::Event_timed()
*/
Event_timed::Event_timed():in_spawned_thread(0),locked_by_thread_id(0),
running(0), thread_id(0), status_changed(false),
last_executed_changed(false), expression(0),
created(0), modified(0),
on_completion(Event_timed::ON_COMPLETION_DROP),
status(Event_timed::ENABLED), sphead(0),
sql_mode(0), body_begin(0), dropped(false),
free_sphead_on_delete(true), flags(0)
{
pthread_mutex_init(&this->LOCK_running, MY_MUTEX_INIT_FAST);
pthread_cond_init(&this->COND_finished, NULL);
init();
}
/*
Destructor
SYNOPSIS
Event_timed::~Event_timed()
*/
Event_timed::~Event_timed()
{
deinit_mutexes();
if (free_sphead_on_delete)
free_sp();
}
/*
Destructor
SYNOPSIS
Event_timed::~deinit_mutexes()
*/
void
Event_timed::deinit_mutexes()
{
pthread_mutex_destroy(&this->LOCK_running);
pthread_cond_destroy(&this->COND_finished);
}
/*
Checks whether the event is running
SYNOPSIS
Event_timed::is_running()
*/
bool
Event_timed::is_running()
{
bool ret;
VOID(pthread_mutex_lock(&this->LOCK_running));
ret= running;
VOID(pthread_mutex_unlock(&this->LOCK_running));
return ret;
}
/*
Init all member variables
SYNOPSIS
Event_timed::init()
*/
void
Event_timed::init()
{
DBUG_ENTER("Event_timed::init");
dbname.str= name.str= body.str= comment.str= 0;
dbname.length= name.length= body.length= comment.length= 0;
status= ENABLED;
on_completion= ON_COMPLETION_DROP;
expression= 0;
/* Actually in the parser STARTS is always set */
set_zero_time(&starts, MYSQL_TIMESTAMP_DATETIME);
set_zero_time(&ends, MYSQL_TIMESTAMP_DATETIME);
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
set_zero_time(&last_executed, MYSQL_TIMESTAMP_DATETIME);
starts_null= ends_null= execute_at_null= TRUE;
definer_user.str= definer_host.str= 0;
definer_user.length= definer_host.length= 0;
sql_mode= 0;
DBUG_VOID_RETURN;
body.str= comment.str= 0;
body.length= comment.length= 0;
}
......@@ -222,37 +54,25 @@ Event_timed::init()
Set a name of the event
SYNOPSIS
Event_timed::init_name()
Event_parse_data::init_name()
thd THD
spn the name extracted in the parser
*/
void
Event_timed::init_name(THD *thd, sp_name *spn)
Event_parse_data::init_name(THD *thd, sp_name *spn)
{
DBUG_ENTER("Event_timed::init_name");
/* During parsing, we must use thd->mem_root */
MEM_ROOT *root= thd->mem_root;
DBUG_ENTER("Event_parse_data::init_name");
/* We have to copy strings to get them into the right memroot */
if (spn)
{
dbname.length= spn->m_db.length;
if (spn->m_db.length == 0)
dbname.str= NULL;
else
dbname.str= strmake_root(root, spn->m_db.str, spn->m_db.length);
name.length= spn->m_name.length;
name.str= strmake_root(root, spn->m_name.str, spn->m_name.length);
if (spn->m_qname.length == 0)
spn->init_qname(thd);
}
else if (thd->db)
{
dbname.length= thd->db_length;
dbname.str= strmake_root(root, thd->db, dbname.length);
}
DBUG_ASSERT(spn);
dbname.length= spn->m_db.length;
if (spn->m_db.length == 0)
dbname.str= NULL;
else
dbname.str= thd->strmake(spn->m_db.str, spn->m_db.length);
name.length= spn->m_name.length;
name.str= thd->strmake(spn->m_name.str, spn->m_name.length);
DBUG_PRINT("dbname", ("len=%d db=%s",dbname.length, dbname.str));
DBUG_PRINT("name", ("len=%d name=%s",name.length, name.str));
......@@ -265,7 +85,7 @@ Event_timed::init_name(THD *thd, sp_name *spn)
Set body of the event - what should be executed.
SYNOPSIS
Event_timed::init_body()
Event_parse_data::init_body()
thd THD
NOTE
......@@ -277,9 +97,9 @@ Event_timed::init_name(THD *thd, sp_name *spn)
*/
void
Event_timed::init_body(THD *thd)
Event_parse_data::init_body(THD *thd)
{
DBUG_ENTER("Event_timed::init_body");
DBUG_ENTER("Event_parse_data::init_body");
DBUG_PRINT("info", ("body=[%s] body_begin=0x%ld end=0x%ld", body_begin,
body_begin, thd->lex->ptr));
......@@ -331,17 +151,60 @@ Event_timed::init_body(THD *thd)
++body_begin;
--body.length;
}
body.str= strmake_root(thd->mem_root, (char *)body_begin, body.length);
body.str= thd->strmake((char *)body_begin, body.length);
DBUG_VOID_RETURN;
}
/*
Inits definer (definer_user and definer_host) during parsing.
SYNOPSIS
Event_parse_data::init_definer()
RETURN VALUE
0 OK
*/
int
Event_parse_data::init_definer(THD *thd)
{
int definer_user_len;
int definer_host_len;
DBUG_ENTER("Event_parse_data::init_definer");
DBUG_PRINT("info",("init definer_user thd->mem_root=0x%lx "
"thd->sec_ctx->priv_user=0x%lx", thd->mem_root,
thd->security_ctx->priv_user));
definer_user_len= strlen(thd->security_ctx->priv_user);
definer_host_len= strlen(thd->security_ctx->priv_host);
/* + 1 for @ */
DBUG_PRINT("info",("init definer as whole"));
definer.length= definer_user_len + definer_host_len + 1;
definer.str= thd->alloc(definer.length + 1);
DBUG_PRINT("info",("copy the user"));
memcpy(definer.str, thd->security_ctx->priv_user, definer_user_len);
definer.str[definer_user_len]= '@';
DBUG_PRINT("info",("copy the host"));
memcpy(definer.str + definer_user_len + 1, thd->security_ctx->priv_host,
definer_host_len);
definer.str[definer.length]= '\0';
DBUG_PRINT("info",("definer [%s] initted", definer.str));
DBUG_RETURN(0);
}
/*
Set time for execution for one time events.
SYNOPSIS
Event_timed::init_execute_at()
Event_parse_data::init_execute_at()
expr when (datetime)
RETURN VALUE
......@@ -352,14 +215,14 @@ Event_timed::init_body(THD *thd)
*/
int
Event_timed::init_execute_at(THD *thd, Item *expr)
Event_parse_data::init_execute_at(THD *thd, Item *expr)
{
my_bool not_used;
TIME ltime;
my_time_t t;
TIME time_tmp;
DBUG_ENTER("Event_timed::init_execute_at");
DBUG_ENTER("Event_parse_data::init_execute_at");
if (expr->fix_fields(thd, &expr))
DBUG_RETURN(EVEX_PARSE_ERROR);
......@@ -368,7 +231,7 @@ Event_timed::init_execute_at(THD *thd, Item *expr)
DBUG_PRINT("info", ("starts_null && ends_null should be 1 is %d",
(starts_null && ends_null)));
DBUG_ASSERT(starts_null && ends_null);
/* let's check whether time is in the past */
thd->variables.time_zone->gmt_sec_to_TIME(&time_tmp,
(my_time_t) thd->query_start());
......@@ -403,7 +266,7 @@ Event_timed::init_execute_at(THD *thd, Item *expr)
Set time for execution for transient events.
SYNOPSIS
Event_timed::init_interval()
Event_parse_data::init_interval()
expr how much?
new_interval what is the interval
......@@ -415,12 +278,12 @@ Event_timed::init_execute_at(THD *thd, Item *expr)
*/
int
Event_timed::init_interval(THD *thd, Item *expr, interval_type new_interval)
Event_parse_data::init_interval(THD *thd, Item *expr, interval_type new_interval)
{
String value;
INTERVAL interval_tmp;
DBUG_ENTER("Event_timed::init_interval");
DBUG_ENTER("Event_parse_data::init_interval");
if (expr->fix_fields(thd, &expr))
DBUG_RETURN(EVEX_PARSE_ERROR);
......@@ -504,9 +367,9 @@ Event_timed::init_interval(THD *thd, Item *expr, interval_type new_interval)
Set activation time.
SYNOPSIS
Event_timed::init_starts()
expr how much?
interval what is the interval
Event_parse_data::init_starts()
expr how much?
interval what is the interval
NOTES
Note that activation time is not execution time.
......@@ -523,13 +386,13 @@ Event_timed::init_interval(THD *thd, Item *expr, interval_type new_interval)
*/
int
Event_timed::init_starts(THD *thd, Item *new_starts)
Event_parse_data::init_starts(THD *thd, Item *new_starts)
{
my_bool not_used;
TIME ltime, time_tmp;
my_time_t t;
DBUG_ENTER("Event_timed::init_starts");
DBUG_ENTER("Event_parse_data::init_starts");
if (new_starts->fix_fields(thd, &new_starts))
DBUG_RETURN(EVEX_PARSE_ERROR);
......@@ -570,7 +433,7 @@ Event_timed::init_starts(THD *thd, Item *new_starts)
Set deactivation time.
SYNOPSIS
Event_timed::init_ends()
Event_parse_data::init_ends()
thd THD
new_ends when?
......@@ -590,13 +453,13 @@ Event_timed::init_starts(THD *thd, Item *new_starts)
*/
int
Event_timed::init_ends(THD *thd, Item *new_ends)
Event_parse_data::init_ends(THD *thd, Item *new_ends)
{
TIME ltime, ltime_now;
my_bool not_used;
my_time_t t;
DBUG_ENTER("Event_timed::init_ends");
DBUG_ENTER("Event_parse_data::init_ends");
if (new_ends->fix_fields(thd, &new_ends))
DBUG_RETURN(EVEX_PARSE_ERROR);
......@@ -641,67 +504,106 @@ Event_timed::init_ends(THD *thd, Item *new_ends)
/*
Sets comment.
Constructor
SYNOPSIS
Event_timed::init_comment()
thd THD - used for memory allocation
comment the string.
Event_timed::Event_timed()
*/
void
Event_timed::init_comment(THD *thd, LEX_STRING *set_comment)
Event_timed::Event_timed():in_spawned_thread(0),locked_by_thread_id(0),
running(0), thread_id(0), status_changed(false),
last_executed_changed(false), expression(0),
created(0), modified(0),
on_completion(Event_timed::ON_COMPLETION_DROP),
status(Event_timed::ENABLED), sphead(0),
sql_mode(0), dropped(false),
free_sphead_on_delete(true), flags(0)
{
DBUG_ENTER("Event_timed::init_comment");
pthread_mutex_init(&this->LOCK_running, MY_MUTEX_INIT_FAST);
pthread_cond_init(&this->COND_finished, NULL);
init();
}
comment.str= strmake_root(thd->mem_root, set_comment->str,
comment.length= set_comment->length);
DBUG_VOID_RETURN;
/*
Destructor
SYNOPSIS
Event_timed::~Event_timed()
*/
Event_timed::~Event_timed()
{
deinit_mutexes();
if (free_sphead_on_delete)
free_sp();
}
/*
Inits definer (definer_user and definer_host) during parsing.
Destructor
SYNOPSIS
Event_timed::init_definer()
RETURN VALUE
0 OK
Event_timed::deinit_mutexes()
*/
int
Event_timed::init_definer(THD *thd)
void
Event_timed::deinit_mutexes()
{
DBUG_ENTER("Event_timed::init_definer");
pthread_mutex_destroy(&this->LOCK_running);
pthread_cond_destroy(&this->COND_finished);
}
DBUG_PRINT("info",("init definer_user thd->mem_root=0x%lx "
"thd->sec_ctx->priv_user=0x%lx", thd->mem_root,
thd->security_ctx->priv_user));
definer_user.str= strdup_root(thd->mem_root, thd->security_ctx->priv_user);
definer_user.length= strlen(thd->security_ctx->priv_user);
DBUG_PRINT("info",("init definer_host thd->s_c->priv_host=0x%lx",
thd->security_ctx->priv_host));
definer_host.str= strdup_root(thd->mem_root, thd->security_ctx->priv_host);
definer_host.length= strlen(thd->security_ctx->priv_host);
/*
Checks whether the event is running
DBUG_PRINT("info",("init definer as whole"));
definer.length= definer_user.length + definer_host.length + 1;
definer.str= alloc_root(thd->mem_root, definer.length + 1);
SYNOPSIS
Event_timed::is_running()
*/
DBUG_PRINT("info",("copy the user"));
memcpy(definer.str, definer_user.str, definer_user.length);
definer.str[definer_user.length]= '@';
bool
Event_timed::is_running()
{
bool ret;
DBUG_PRINT("info",("copy the host"));
memcpy(definer.str + definer_user.length + 1, definer_host.str,
definer_host.length);
definer.str[definer.length]= '\0';
DBUG_PRINT("info",("definer initted"));
VOID(pthread_mutex_lock(&this->LOCK_running));
ret= running;
VOID(pthread_mutex_unlock(&this->LOCK_running));
DBUG_RETURN(0);
return ret;
}
/*
Init all member variables
SYNOPSIS
Event_timed::init()
*/
void
Event_timed::init()
{
DBUG_ENTER("Event_timed::init");
dbname.str= name.str= body.str= comment.str= 0;
dbname.length= name.length= body.length= comment.length= 0;
set_zero_time(&starts, MYSQL_TIMESTAMP_DATETIME);
set_zero_time(&ends, MYSQL_TIMESTAMP_DATETIME);
set_zero_time(&execute_at, MYSQL_TIMESTAMP_DATETIME);
set_zero_time(&last_executed, MYSQL_TIMESTAMP_DATETIME);
starts_null= ends_null= execute_at_null= TRUE;
definer_user.str= definer_host.str= 0;
definer_user.length= definer_host.length= 0;
sql_mode= 0;
DBUG_VOID_RETURN;
}
......@@ -739,20 +641,17 @@ Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
if (table->s->fields != ET_FIELD_COUNT)
goto error;
if ((et->dbname.str= get_field(mem_root,
table->field[ET_FIELD_DB])) == NULL)
if ((et->dbname.str= get_field(mem_root, table->field[ET_FIELD_DB])) == NULL)
goto error;
et->dbname.length= strlen(et->dbname.str);
if ((et->name.str= get_field(mem_root,
table->field[ET_FIELD_NAME])) == NULL)
if ((et->name.str= get_field(mem_root, table->field[ET_FIELD_NAME])) == NULL)
goto error;
et->name.length= strlen(et->name.str);
if ((et->body.str= get_field(mem_root,
table->field[ET_FIELD_BODY])) == NULL)
if ((et->body.str= get_field(mem_root, table->field[ET_FIELD_BODY])) == NULL)
goto error;
et->body.length= strlen(et->body.str);
......@@ -837,7 +736,6 @@ Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
et->comment.length= strlen(et->comment.str);
else
et->comment.length= 0;
et->sql_mode= (ulong) table->field[ET_FIELD_SQL_MODE]->val_int();
......@@ -858,7 +756,7 @@ Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
time_now current time
i_value quantity of time type interval to add
i_type type of interval to add (SECOND, MINUTE, HOUR, WEEK ...)
RETURN VALUE
0 OK
1 Error
......@@ -1639,7 +1537,6 @@ Event_timed::compile(THD *thd, MEM_ROOT *mem_root)
&security_ctx, &save_ctx);
thd->lex= &lex;
lex_start(thd, (uchar*)thd->query, thd->query_length);
lex.et_compile_phase= TRUE;
if (MYSQLparse((void *)thd) || thd->is_fatal_error)
{
DBUG_PRINT("error", ("error during compile or thd->is_fatal_error=%d",
......@@ -1662,7 +1559,7 @@ Event_timed::compile(THD *thd, MEM_ROOT *mem_root)
}
DBUG_PRINT("note", ("success compiling %s.%s", dbname.str, name.str));
sphead= lex.et->sphead;
sphead= lex.sphead;
sphead->m_db= dbname;
sphead->set_definer(definer.str, definer.length);
......@@ -1670,8 +1567,6 @@ Event_timed::compile(THD *thd, MEM_ROOT *mem_root)
sphead->optimize();
ret= 0;
done:
lex.et->free_sphead_on_delete= false;
lex.et->deinit_mutexes();
lex_end(&lex);
thd->restore_security_context(save_ctx);
......@@ -1709,7 +1604,7 @@ extern pthread_attr_t connection_attrib;
int
Event_timed::spawn_now(void * (*thread_func)(void*), void *arg)
{
{
THD *thd= current_thd;
int ret= EVENT_EXEC_STARTED;
DBUG_ENTER("Event_timed::spawn_now");
......@@ -1875,7 +1770,6 @@ event_timed_db_equal(Event_timed *et, LEX_STRING *db)
}
/*
Checks whether two events are equal by identifiers
......@@ -1888,121 +1782,8 @@ event_timed_db_equal(Event_timed *et, LEX_STRING *db)
*/
bool
event_timed_identifier_equal(Event_timed *a, Event_timed *b)
event_timed_identifier_equal(LEX_STRING db, LEX_STRING name, Event_timed *b)
{
return event_timed_name_equal(a, &b->name) &&
event_timed_db_equal(a, &b->dbname);
}
/*
Checks whether two events have the same name
SYNOPSIS
event_timed_name_equal()
RETURN VALUE
TRUE names are equal
FALSE names are not equal
*/
bool
event_timed_name_equal(sp_name *name, LEX_STRING *event_name)
{
return !sortcmp_lex_string(name->m_name, *event_name, system_charset_info);
}
/*
Checks whether two events are in the same schema
SYNOPSIS
event_timed_db_equal()
RETURN VALUE
TRUE schemas are equal
FALSE schemas are not equal
*/
bool
event_timed_db_equal(sp_name *name, LEX_STRING *db)
{
return !sortcmp_lex_string(name->m_db, *db, system_charset_info);
}
/*
Checks whether two events are equal by identifiers
SYNOPSIS
event_timed_identifier_equal()
RETURN VALUE
TRUE equal
FALSE not equal
*/
bool
event_timed_identifier_equal(sp_name *a, Event_timed *b)
{
return event_timed_name_equal(a, &b->name) &&
event_timed_db_equal(a, &b->dbname);
}
/*
Switches the security context
SYNOPSIS
change_security_context()
thd Thread
user The user
host The host of the user
db The schema for which the security_ctx will be loaded
s_ctx Security context to load state into
backup Where to store the old context
RETURN VALUE
0 - OK
1 - Error (generates error too)
*/
bool
change_security_context(THD *thd, LEX_STRING user, LEX_STRING host,
LEX_STRING db, Security_context *s_ctx,
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))
{
my_error(ER_NO_SUCH_USER, MYF(0), user.str, host.str);
DBUG_RETURN(TRUE);
}
*backup= thd->security_ctx;
thd->security_ctx= s_ctx;
#endif
DBUG_RETURN(FALSE);
}
/*
Restores the security context
SYNOPSIS
restore_security_context()
thd - thread
backup - switch to this context
*/
void
restore_security_context(THD *thd, Security_context *backup)
{
DBUG_ENTER("restore_security_context");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (backup)
thd->security_ctx= backup;
#endif
DBUG_VOID_RETURN;
return !sortcmp_lex_string(name, b->name, system_charset_info) &&
!sortcmp_lex_string(db, b->dbname, system_charset_info);
}
......@@ -54,19 +54,9 @@ class Event_timed;
bool
event_timed_db_equal(Event_timed *et, LEX_STRING *db);
/* Compares the whole identifier*/
bool
event_timed_identifier_equal(Event_timed *a, Event_timed *b);
/* Compares only the schema part of the identifier */
bool
event_timed_db_equal(sp_name *name, LEX_STRING *db);
/* Compares the whole identifier*/
bool
event_timed_identifier_equal(sp_name *a, Event_timed *b);
event_timed_identifier_equal(LEX_STRING db, LEX_STRING name, Event_timed *b);
class Event_timed
......@@ -123,7 +113,6 @@ class Event_timed
enum enum_status status;
sp_head *sphead;
ulong sql_mode;
const uchar *body_begin;
bool dropped;
bool free_sphead_on_delete;
......@@ -138,9 +127,6 @@ class Event_timed
DBUG_RETURN(p);
}
static void *operator new(size_t size, MEM_ROOT *mem_root)
{ return (void*) alloc_root(mem_root, (uint) size); }
static void operator delete(void *ptr, size_t size)
{
DBUG_ENTER("Event_timed::delete(ptr,size)");
......@@ -150,17 +136,6 @@ class Event_timed
DBUG_VOID_RETURN;
}
static void operator delete(void *ptr, MEM_ROOT *mem_root)
{
/*
Don't free the memory it will be done by the mem_root but
we need to call the destructor because we free other resources
which are not allocated on the root but on the heap, or we
deinit mutexes.
*/
DBUG_ASSERT(0);
}
Event_timed();
~Event_timed();
......@@ -171,30 +146,6 @@ class Event_timed
void
deinit_mutexes();
int
init_definer(THD *thd);
int
init_execute_at(THD *thd, Item *expr);
int
init_interval(THD *thd, Item *expr, interval_type new_interval);
void
init_name(THD *thd, sp_name *spn);
int
init_starts(THD *thd, Item *starts);
int
init_ends(THD *thd, Item *ends);
void
init_body(THD *thd);
void
init_comment(THD *thd, LEX_STRING *set_comment);
int
load_from_row(MEM_ROOT *mem_root, TABLE *table);
......@@ -231,9 +182,6 @@ class Event_timed
void
free_sp();
bool
has_equal_db(Event_timed *etn);
int
kill_thread(THD *thd);
......@@ -268,12 +216,9 @@ class Event_parse_data : public Sql_alloc
LEX_STRING dbname;
LEX_STRING name;
LEX_STRING body;
LEX_STRING definer_user;
LEX_STRING definer_host;
LEX_STRING definer;// combination of user and host
LEX_STRING comment;
Item* item_starts;
Item* item_ends;
Item* item_execute_at;
......@@ -316,10 +261,6 @@ class Event_parse_data : public Sql_alloc
void
init_body(THD *thd);
void
init_comment(THD *thd, LEX_STRING *set_comment);
};
......
......@@ -34,7 +34,7 @@ TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] = {
{(char *) STRING_WITH_LEN("db")},
{(char *) STRING_WITH_LEN("char(64)")},
{(char *) STRING_WITH_LEN("utf8")}
},
},
{
{(char *) STRING_WITH_LEN("name")},
{(char *) STRING_WITH_LEN("char(64)")},
......@@ -44,7 +44,7 @@ TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] = {
{(char *) STRING_WITH_LEN("body")},
{(char *) STRING_WITH_LEN("longblob")},
{NULL, 0}
},
},
{
{(char *) STRING_WITH_LEN("definer")},
{(char *) STRING_WITH_LEN("char(77)")},
......@@ -54,7 +54,7 @@ TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] = {
{(char *) STRING_WITH_LEN("execute_at")},
{(char *) STRING_WITH_LEN("datetime")},
{NULL, 0}
},
},
{
{(char *) STRING_WITH_LEN("interval_value")},
{(char *) STRING_WITH_LEN("int(11)")},
......@@ -68,7 +68,7 @@ TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] = {
"'DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND',"
"'SECOND_MICROSECOND')")},
{NULL, 0}
},
},
{
{(char *) STRING_WITH_LEN("created")},
{(char *) STRING_WITH_LEN("timestamp")},
......@@ -78,7 +78,7 @@ TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] = {
{(char *) STRING_WITH_LEN("modified")},
{(char *) STRING_WITH_LEN("timestamp")},
{NULL, 0}
},
},
{
{(char *) STRING_WITH_LEN("last_executed")},
{(char *) STRING_WITH_LEN("datetime")},
......@@ -88,7 +88,7 @@ TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] = {
{(char *) STRING_WITH_LEN("starts")},
{(char *) STRING_WITH_LEN("datetime")},
{NULL, 0}
},
},
{
{(char *) STRING_WITH_LEN("ends")},
{(char *) STRING_WITH_LEN("datetime")},
......@@ -98,7 +98,7 @@ TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] = {
{(char *) STRING_WITH_LEN("status")},
{(char *) STRING_WITH_LEN("enum('ENABLED','DISABLED')")},
{NULL, 0}
},
},
{
{(char *) STRING_WITH_LEN("on_completion")},
{(char *) STRING_WITH_LEN("enum('DROP','PRESERVE')")},
......@@ -186,6 +186,133 @@ evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update)
goto err_truncate;
}
if (et->expression)
{
table->field[ET_FIELD_INTERVAL_EXPR]->set_notnull();
table->field[ET_FIELD_INTERVAL_EXPR]->store((longlong)et->expression, true);
table->field[ET_FIELD_TRANSIENT_INTERVAL]->set_notnull();
/*
In the enum (C) intervals start from 0 but in mysql enum valid values start
from 1. Thus +1 offset is needed!
*/
table->field[ET_FIELD_TRANSIENT_INTERVAL]->
store((longlong)et->interval+1, true);
table->field[ET_FIELD_EXECUTE_AT]->set_null();
if (!et->starts_null)
{
table->field[ET_FIELD_STARTS]->set_notnull();
table->field[ET_FIELD_STARTS]->
store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
}
if (!et->ends_null)
{
table->field[ET_FIELD_ENDS]->set_notnull();
table->field[ET_FIELD_ENDS]->
store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
}
}
else if (et->execute_at.year)
{
table->field[ET_FIELD_INTERVAL_EXPR]->set_null();
table->field[ET_FIELD_TRANSIENT_INTERVAL]->set_null();
table->field[ET_FIELD_STARTS]->set_null();
table->field[ET_FIELD_ENDS]->set_null();
table->field[ET_FIELD_EXECUTE_AT]->set_notnull();
table->field[ET_FIELD_EXECUTE_AT]->
store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME);
}
else
{
DBUG_ASSERT(is_update);
/*
it is normal to be here when the action is update
this is an error if the action is create. something is borked
*/
}
((Field_timestamp *)table->field[ET_FIELD_MODIFIED])->set_time();
if (et->comment.str)
{
if (table->field[field_num= ET_FIELD_COMMENT]->
store(et->comment.str, et->comment.length, scs))
goto err_truncate;
}
DBUG_RETURN(0);
err_truncate:
my_error(ER_EVENT_DATA_TOO_LONG, MYF(0), table->field[field_num]->field_name);
DBUG_RETURN(EVEX_GENERAL_ERROR);
}
/*
Puts some data common to CREATE and ALTER EVENT into a row.
SYNOPSIS
evex_fill_row()
thd THD
table the row to fill out
et Event's data
RETURN VALUE
0 - OK
EVEX_GENERAL_ERROR - bad data
EVEX_GET_FIELD_FAILED - field count does not match. table corrupted?
DESCRIPTION
Used both when an event is created and when it is altered.
*/
static int
evex_fill_row(THD *thd, TABLE *table, Event_parse_data *et, my_bool is_update)
{
CHARSET_INFO *scs= system_charset_info;
enum enum_events_table_field field_num;
DBUG_ENTER("evex_fill_row");
DBUG_PRINT("info", ("dbname=[%s]", et->dbname.str));
DBUG_PRINT("info", ("name =[%s]", et->name.str));
DBUG_PRINT("info", ("body =[%s]", et->body.str));
if (table->field[field_num= ET_FIELD_DEFINER]->
store(et->definer.str, et->definer.length, scs))
goto err_truncate;
if (table->field[field_num= ET_FIELD_DB]->
store(et->dbname.str, et->dbname.length, scs))
goto err_truncate;
if (table->field[field_num= ET_FIELD_NAME]->
store(et->name.str, et->name.length, scs))
goto err_truncate;
/* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()*/
table->field[ET_FIELD_ON_COMPLETION]->
store((longlong)et->on_completion, true);
table->field[ET_FIELD_STATUS]->store((longlong)et->status, true);
/*
Change the SQL_MODE only if body was present in an ALTER EVENT and of course
always during CREATE EVENT.
*/
if (et->body.str)
{
table->field[ET_FIELD_SQL_MODE]->
store((longlong)thd->variables.sql_mode, true);
if (table->field[field_num= ET_FIELD_BODY]->
store(et->body.str, et->body.length, scs))
goto err_truncate;
}
if (et->expression)
{
table->field[ET_FIELD_INTERVAL_EXPR]->set_notnull();
......@@ -462,14 +589,15 @@ Event_db_repository::fill_schema_events(THD *thd, TABLE_LIST *tables, char *db)
*/
int
Event_db_repository::find_event(THD *thd, sp_name *name, Event_timed **ett,
Event_db_repository::find_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
Event_timed **ett,
TABLE *tbl, MEM_ROOT *root)
{
TABLE *table;
int ret;
Event_timed *et= NULL;
DBUG_ENTER("db_find_event");
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
DBUG_PRINT("enter", ("name: %*s", name.length, name.str));
if (tbl)
table= tbl;
......@@ -480,22 +608,22 @@ Event_db_repository::find_event(THD *thd, sp_name *name, Event_timed **ett,
goto done;
}
if ((ret= evex_db_find_event_by_name(thd, name->m_db, name->m_name, table)))
if ((ret= evex_db_find_event_by_name(thd, dbname, name, table)))
{
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name->m_name.str);
goto done;
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
goto done;
}
et= new Event_timed;
/*
1)The table should not be closed beforehand. ::load_from_row() only loads
1)The table should not be closed beforehand. ::load_from_row() only loads
and does not compile
2)::load_from_row() is silent on error therefore we emit error msg here
*/
if ((ret= et->load_from_row(root, table)))
{
my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0));
my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
goto done;
}
......@@ -557,7 +685,7 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type,
if (simple_open_n_lock_tables(thd, &tables))
DBUG_RETURN(1);
if (table_check_intact(tables.table, ET_FIELD_COUNT,
event_table_fields,
&mysql_event_last_create_time,
......@@ -572,6 +700,118 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type,
}
/*
Checks parameters which we got from the parsing phase.
SYNOPSIS
evex_check_params()
thd THD
et event's data
RETURNS
0 OK
EVEX_BAD_PARAMS Error
REMARKS
Issues error messages
*/
int
evex_check_params(THD *thd, Event_parse_data *parse_data)
{
const char *pos= NULL;
Item *bad_item;
DBUG_ENTER("evex_check_timing_params");
DBUG_PRINT("info", ("execute_at=0x%d expr=0x%d starts=0x%d ends=0x%d",
parse_data->item_execute_at,
parse_data->item_expression,
parse_data->item_starts,
parse_data->item_ends));
parse_data->init_name(thd, parse_data->identifier);
parse_data->init_definer(thd);
if (!parse_data->dbname.str ||
(thd->lex->sql_command == SQLCOM_ALTER_EVENT && thd->lex->spname &&
!thd->lex->spname->m_db.str))
{
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
DBUG_RETURN(EVEX_BAD_PARAMS);
}
if (check_access(thd, EVENT_ACL, parse_data->dbname.str, 0, 0, 0,
is_schema_db(parse_data->dbname.str)) ||
(thd->lex->sql_command == SQLCOM_ALTER_EVENT && thd->lex->spname &&
(check_access(thd, EVENT_ACL, thd->lex->spname->m_db.str, 0, 0, 0,
is_schema_db(thd->lex->spname->m_db.str)))))
DBUG_RETURN(EVEX_BAD_PARAMS);
if (parse_data->item_execute_at)
{
DBUG_PRINT("info", ("ONE TIME"));
if (parse_data->init_execute_at(thd, parse_data->item_execute_at))
{
pos= "AT";
bad_item= parse_data->item_execute_at;
goto wrong_value;
}
}
else
{
int res;
DBUG_PRINT("info", ("RECURRING"));
if (parse_data->item_expression &&
(res= parse_data->init_interval(thd, parse_data->item_expression,
parse_data->interval)))
{
switch (res) {
case EVEX_BAD_PARAMS:
my_error(ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG, MYF(0));
break;
case EVEX_MICROSECOND_UNSUP:
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND");
break;
default:
pos= "INTERVAL";
bad_item= parse_data->item_expression;
goto wrong_value;
}
DBUG_RETURN(EVEX_BAD_PARAMS);
}
if (parse_data->item_starts &&
parse_data->init_starts(thd, parse_data->item_starts))
{
pos= "STARTS";
bad_item= parse_data->item_starts;
goto wrong_value;
}
if (parse_data->item_ends &&
parse_data->init_ends(thd, parse_data->item_ends))
{
/*
despite the error name the value is
eng "ENDS is either invalid or before STARTS"
*/
my_error(ER_EVENT_ENDS_BEFORE_STARTS, MYF(0));
DBUG_RETURN(EVEX_BAD_PARAMS);
}
}
DBUG_RETURN(0);
wrong_value:
{
char buff[120];
String str(buff,(uint32) sizeof(buff), system_charset_info);
String *str2= bad_item->fixed? bad_item->val_str(&str):NULL;
my_error(ER_WRONG_VALUE, MYF(0), pos, str2? str2->c_ptr():"NULL");
DBUG_RETURN(EVEX_BAD_PARAMS);
}
}
/*
Creates an event in mysql.event
......@@ -592,7 +832,7 @@ Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type,
*/
int
Event_db_repository::create_event(THD *thd, Event_timed *et,
Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
my_bool create_if_not, uint *rows_affected)
{
int ret= 0;
......@@ -601,7 +841,6 @@ Event_db_repository::create_event(THD *thd, Event_timed *et,
char olddb[128];
bool dbchanged= false;
DBUG_ENTER("Event_db_repository::create_event");
DBUG_PRINT("enter", ("name: %.*s", et->name.length, et->name.str));
*rows_affected= 0;
DBUG_PRINT("info", ("open mysql.event for update"));
......@@ -611,22 +850,28 @@ Event_db_repository::create_event(THD *thd, Event_timed *et,
goto err;
}
if (evex_check_params(thd, parse_data))
goto err;
DBUG_PRINT("info", ("name: %.*s", parse_data->name.length,
parse_data->name.str));
DBUG_PRINT("info", ("check existance of an event with the same name"));
if (!evex_db_find_event_by_name(thd, et->dbname, et->name, table))
if (!evex_db_find_event_by_name(thd, parse_data->dbname, parse_data->name, table))
{
if (create_if_not)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
ER_EVENT_ALREADY_EXISTS, ER(ER_EVENT_ALREADY_EXISTS),
et->name.str);
parse_data->name.str);
goto ok;
}
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), et->name.str);
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), parse_data->name.str);
goto err;
}
DBUG_PRINT("info", ("non-existant, go forward"));
if ((ret= sp_use_new_db(thd, et->dbname.str,olddb, sizeof(olddb),0,
if ((ret= sp_use_new_db(thd, parse_data->dbname.str, olddb, sizeof(olddb), 0,
&dbchanged)))
{
my_error(ER_BAD_DB_ERROR, MYF(0));
......@@ -635,28 +880,30 @@ Event_db_repository::create_event(THD *thd, Event_timed *et,
restore_record(table, s->default_values); // Get default values for fields
if (system_charset_info->cset->numchars(system_charset_info, et->dbname.str,
et->dbname.str + et->dbname.length)
> EVEX_DB_FIELD_LEN)
if (system_charset_info->cset->
numchars(system_charset_info, parse_data->dbname.str,
parse_data->dbname.str +
parse_data->dbname.length) > EVEX_DB_FIELD_LEN)
{
my_error(ER_TOO_LONG_IDENT, MYF(0), et->dbname.str);
my_error(ER_TOO_LONG_IDENT, MYF(0), parse_data->dbname.str);
goto err;
}
if (system_charset_info->cset->numchars(system_charset_info, et->name.str,
et->name.str + et->name.length)
> EVEX_DB_FIELD_LEN)
if (system_charset_info->cset->
numchars(system_charset_info, parse_data->name.str,
parse_data->name.str +
parse_data->name.length) > EVEX_DB_FIELD_LEN)
{
my_error(ER_TOO_LONG_IDENT, MYF(0), et->name.str);
my_error(ER_TOO_LONG_IDENT, MYF(0), parse_data->name.str);
goto err;
}
if (et->body.length > table->field[ET_FIELD_BODY]->field_length)
if (parse_data->body.length > table->field[ET_FIELD_BODY]->field_length)
{
my_error(ER_TOO_LONG_BODY, MYF(0), et->name.str);
my_error(ER_TOO_LONG_BODY, MYF(0), parse_data->name.str);
goto err;
}
if (!(et->expression) && !(et->execute_at.year))
if (!(parse_data->expression) && !(parse_data->execute_at.year))
{
DBUG_PRINT("error", ("neither expression nor execute_at are set!"));
my_error(ER_EVENT_NEITHER_M_EXPR_NOR_M_AT, MYF(0));
......@@ -669,12 +916,16 @@ Event_db_repository::create_event(THD *thd, Event_timed *et,
evex_fill_row() calls my_error() in case of error so no need to
handle it here
*/
if ((ret= evex_fill_row(thd, table, et, false)))
if ((ret= evex_fill_row(thd, table, parse_data, false)))
goto err;
/* Close active transaction only if We are going to modify disk */
if (end_active_trans(thd))
goto err;
if (table->file->ha_write_row(table->record[0]))
{
my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret);
my_error(ER_EVENT_STORE_FAILED, MYF(0), parse_data->name.str, ret);
goto err;
}
......@@ -724,40 +975,44 @@ Event_db_repository::create_event(THD *thd, Event_timed *et,
*/
int
Event_db_repository::update_event(THD *thd, Event_timed *et, sp_name *new_name)
Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
sp_name *new_name)
{
CHARSET_INFO *scs= system_charset_info;
TABLE *table;
int ret= EVEX_OPEN_TABLE_FAILED;
DBUG_ENTER("Event_db_repository::update_event");
DBUG_PRINT("enter", ("dbname: %.*s", et->dbname.length, et->dbname.str));
DBUG_PRINT("enter", ("name: %.*s", et->name.length, et->name.str));
DBUG_PRINT("enter", ("user: %.*s", et->definer.length, et->definer.str));
if (new_name)
DBUG_PRINT("enter", ("rename to: %.*s", new_name->m_name.length,
new_name->m_name.str));
if (open_event_table(thd, TL_WRITE, &table))
{
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
goto err;
}
if (evex_check_params(thd, parse_data))
goto err;
DBUG_PRINT("info", ("dbname: %s", parse_data->dbname.str));
DBUG_PRINT("info", ("name: %s", parse_data->name.str));
DBUG_PRINT("info", ("user: %s", parse_data->definer.str));
if (new_name)
DBUG_PRINT("info", ("rename to: %s", new_name->m_name.str));
/* first look whether we overwrite */
if (new_name)
{
if (!sortcmp_lex_string(et->name, new_name->m_name, scs) &&
!sortcmp_lex_string(et->dbname, new_name->m_db, scs))
if (!sortcmp_lex_string(parse_data->name, new_name->m_name, scs) &&
!sortcmp_lex_string(parse_data->dbname, new_name->m_db, scs))
{
my_error(ER_EVENT_SAME_NAME, MYF(0), et->name.str);
goto err;
my_error(ER_EVENT_SAME_NAME, MYF(0), parse_data->name.str);
goto err;
}
if (!evex_db_find_event_by_name(thd,new_name->m_db,new_name->m_name,table))
{
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->m_name.str);
goto err;
}
}
}
/*
...and then if there is such an event. Don't exchange the blocks
......@@ -765,9 +1020,10 @@ Event_db_repository::update_event(THD *thd, Event_timed *et, sp_name *new_name)
overwrite the key and SE will tell us that it cannot find the already found
row (copied into record[1] later
*/
if (EVEX_KEY_NOT_FOUND == find_event_by_name(thd, et->dbname, et->name, table))
if (EVEX_KEY_NOT_FOUND == find_event_by_name(thd, parse_data->dbname,
parse_data->name, table))
{
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), et->name.str);
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), parse_data->name.str);
goto err;
}
......@@ -780,20 +1036,24 @@ Event_db_repository::update_event(THD *thd, Event_timed *et, sp_name *new_name)
evex_fill_row() calls my_error() in case of error so no need to
handle it here
*/
if ((ret= evex_fill_row(thd, table, et, true)))
if ((ret= evex_fill_row(thd, table, parse_data, true)))
goto err;
if (new_name)
{
{
table->field[ET_FIELD_DB]->
store(new_name->m_db.str, new_name->m_db.length, scs);
table->field[ET_FIELD_NAME]->
store(new_name->m_name.str, new_name->m_name.length, scs);
}
/* Close active transaction only if We are going to modify disk */
if (end_active_trans(thd))
goto err;
if ((ret= table->file->ha_update_row(table->record[1], table->record[0])))
{
my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret);
my_error(ER_EVENT_STORE_FAILED, MYF(0), parse_data->name.str, ret);
goto err;
}
......@@ -845,6 +1105,10 @@ Event_db_repository::drop_event(THD *thd, LEX_STRING db, LEX_STRING name,
if (!(ret= evex_db_find_event_by_name(thd, db, name, table)))
{
/* Close active transaction only if We are going to modify disk */
if ((ret= end_active_trans(thd)))
goto done;
if ((ret= table->file->ha_delete_row(table->record[0])))
my_error(ER_EVENT_CANNOT_DELETE, MYF(0));
}
......@@ -998,7 +1262,7 @@ Event_db_repository::drop_events_by_field(THD *thd,
*/
int
Event_db_repository::load_named_event(THD *thd, Event_timed *etn,
Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
Event_timed **etn_new)
{
int ret= 0;
......@@ -1007,14 +1271,11 @@ Event_db_repository::load_named_event(THD *thd, Event_timed *etn,
Open_tables_state backup;
DBUG_ENTER("Event_scheduler::load_and_compile_event");
DBUG_PRINT("enter",("thd=%p name:%*s",thd, etn->name.length, etn->name.str));
DBUG_PRINT("enter",("thd=%p name:%*s",thd, name.length, name.str));
thd->reset_n_backup_open_tables_state(&backup);
/* No need to use my_error() here because db_find_event() has done it */
{
sp_name spn(etn->dbname, etn->name);
ret= find_event(thd, &spn, &et_loaded, NULL, &repo_root);
}
ret= find_event(thd, dbname, name, &et_loaded, NULL, &repo_root);
thd->restore_backup_open_tables_state(&backup);
/* In this case no memory was allocated so we don't need to clean */
if (ret)
......
......@@ -53,7 +53,8 @@ events_table_scan_all(THD *thd, TABLE *schema_table, TABLE *event_table);
int
fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */);
class Event_timed;
class Event_parse_data;
class Event_queue_element;
class Event_db_repository
......@@ -69,11 +70,11 @@ class Event_db_repository
deinit_repository();
int
create_event(THD *thd, Event_timed *et, my_bool create_if_not,
uint *rows_affected);
create_event(THD *thd, Event_parse_data *parse_data, my_bool create_if_not,
uint *rows_affected);
int
update_event(THD *thd, Event_timed *et, sp_name *new_name);
update_event(THD *thd, Event_parse_data *parse_data, sp_name *new_name);
int
drop_event(THD *thd, LEX_STRING db, LEX_STRING name, bool drop_if_exists,
......@@ -86,11 +87,11 @@ class Event_db_repository
drop_user_events(THD *thd, LEX_STRING definer);
int
find_event(THD *thd, sp_name *name, Event_timed **ett, TABLE *tbl,
MEM_ROOT *root);
find_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_timed **ett,
TABLE *tbl, MEM_ROOT *root);
int
load_named_event(THD *thd, Event_timed *etn, Event_timed **etn_new);
load_named_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_timed **etn_new);
int
find_event_by_name(THD *thd, LEX_STRING db, LEX_STRING name, TABLE *table);
......
......@@ -785,7 +785,7 @@ Event_scheduler::destroy()
*/
int
Event_scheduler::create_event(THD *thd, Event_timed *et, bool check_existence)
Event_scheduler::create_event(THD *thd, Event_parse_data *et, bool check_existence)
{
int res;
Event_timed *et_new;
......@@ -799,14 +799,15 @@ Event_scheduler::create_event(THD *thd, Event_timed *et, bool check_existence)
UNLOCK_SCHEDULER_DATA();
DBUG_RETURN(OP_OK);
}
if (check_existence && find_event(et, FALSE))
if (check_existence && find_event(et->dbname, et->name, FALSE))
{
res= OP_ALREADY_EXISTS;
goto end;
}
/* We need to load the event on scheduler_root */
if (!(res= db_repository->load_named_event(thd, et, &et_new)))
if (!(res= db_repository->
load_named_event(thd, et->dbname, et->name, &et_new)))
{
queue_insert_safe(&queue, (byte *) et_new);
DBUG_PRINT("info", ("Sending COND_new_work"));
......@@ -850,7 +851,7 @@ Event_scheduler::drop_event(THD *thd, sp_name *name)
DBUG_RETURN(OP_OK);
}
if (!(et_old= find_event(name, TRUE)))
if (!(et_old= find_event(name->m_db, name->m_name, TRUE)))
DBUG_PRINT("info", ("No such event found, probably DISABLED"));
UNLOCK_SCHEDULER_DATA();
......@@ -906,7 +907,7 @@ Event_scheduler::drop_event(THD *thd, sp_name *name)
*/
int
Event_scheduler::update_event(THD *thd, Event_timed *et,
Event_scheduler::update_event(THD *thd, Event_parse_data *et,
LEX_STRING *new_schema,
LEX_STRING *new_name)
{
......@@ -931,7 +932,7 @@ Event_scheduler::update_event(THD *thd, Event_timed *et,
DBUG_RETURN(OP_OK);
}
if (!(et_old= find_event(et, TRUE)))
if (!(et_old= find_event(et->dbname, et->name, TRUE)))
DBUG_PRINT("info", ("%s.%s not found cached, probably was DISABLED",
et->dbname.str, et->name.str));
......@@ -948,7 +949,8 @@ Event_scheduler::update_event(THD *thd, Event_timed *et,
1. Error occured
2. If the replace is DISABLED, we don't load it into the queue.
*/
if (!(res= db_repository->load_named_event(thd, et, &et_new)))
if (!(res= db_repository->
load_named_event(thd, et->dbname, et->name, &et_new)))
{
queue_insert_safe(&queue, (byte *) et_new);
DBUG_PRINT("info", ("Sending COND_new_work"));
......@@ -1014,50 +1016,8 @@ Event_scheduler::update_event(THD *thd, Event_timed *et,
SYNOPSIS
Event_scheduler::find_event()
etn The event to find
comparator The function to use for comparing
remove_from_q If found whether to remove from the Q
RETURN VALUE
NULL Not found
otherwise Address
NOTE
The caller should do the locking also the caller is responsible for
actual signalling in case an event is removed from the queue
(signalling COND_new_work for instance).
*/
Event_timed *
Event_scheduler::find_event(Event_timed *etn, bool remove_from_q)
{
uint i;
DBUG_ENTER("Event_scheduler::find_event");
for (i= 0; i < queue.elements; ++i)
{
Event_timed *et= (Event_timed *) queue_element(&queue, i);
DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?", etn->dbname.str, etn->name.str,
et->dbname.str, et->name.str));
if (event_timed_identifier_equal(etn, et))
{
if (remove_from_q)
queue_remove(&queue, i);
DBUG_RETURN(et);
}
}
DBUG_RETURN(NULL);
}
/*
Searches for an event in the scheduler queue
SYNOPSIS
Event_scheduler::find_event()
db The schema of the event to find
name The event to find
comparator The function to use for comparing
remove_from_q If found whether to remove from the Q
RETURN VALUE
......@@ -1071,7 +1031,7 @@ Event_scheduler::find_event(Event_timed *etn, bool remove_from_q)
*/
Event_timed *
Event_scheduler::find_event(sp_name *name, bool remove_from_q)
Event_scheduler::find_event(LEX_STRING db, LEX_STRING name, bool remove_from_q)
{
uint i;
DBUG_ENTER("Event_scheduler::find_event");
......@@ -1079,9 +1039,9 @@ Event_scheduler::find_event(sp_name *name, bool remove_from_q)
for (i= 0; i < queue.elements; ++i)
{
Event_timed *et= (Event_timed *) queue_element(&queue, i);
DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?", name->m_db.str, name->m_name.str,
DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?", db.str, name.str,
et->dbname.str, et->name.str));
if (event_timed_identifier_equal(name, et))
if (event_timed_identifier_equal(db, name, et))
{
if (remove_from_q)
queue_remove(&queue, i);
......@@ -1624,7 +1584,7 @@ Event_scheduler::clean_queue(THD *thd)
SYNOPSIS
Event_scheduler::stop_all_running_events()
thd Thread
NOTE
LOCK_scheduler data must be acquired prior to call to this method
*/
......@@ -1726,7 +1686,7 @@ Event_scheduler::stop()
/*
One situation to be here is if there was a start that forked a new
thread but the new thread did not acquire yet LOCK_scheduler_data.
Hence, in this case return an error.
Hence, in this case return an error.
*/
DBUG_PRINT("info", ("manager not running but %d. doing nothing", state));
UNLOCK_SCHEDULER_DATA();
......@@ -1841,7 +1801,7 @@ Event_scheduler::workers_count()
}
VOID(pthread_mutex_unlock(&LOCK_thread_count));
DBUG_PRINT("exit", ("%d", count));
DBUG_RETURN(count);
DBUG_RETURN(count);
}
......@@ -1851,7 +1811,7 @@ Event_scheduler::workers_count()
SYNOPSIS
Event_scheduler::check_n_suspend_if_needed()
thd Thread
RETURN VALUE
FALSE Not suspended, we haven't slept
TRUE We were suspended. LOCK_scheduler_data is unlocked.
......@@ -1936,7 +1896,7 @@ Event_scheduler::check_n_wait_for_non_empty_queue(THD *thd)
if (!queue.elements)
thd->enter_cond(&cond_vars[COND_new_work], &LOCK_scheduler_data,
"Empty queue, sleeping");
"Empty queue, sleeping");
/* Wait in a loop protecting against catching spurious signals */
while (!queue.elements && state == RUNNING)
......@@ -2079,7 +2039,7 @@ Event_scheduler::get_state()
SYNOPSIS
Event_scheduler::initialized()
RETURN VALUE
FALSE Was not initialized so far
TRUE Was initialized
......
......@@ -57,11 +57,11 @@ class Event_scheduler
/* Methods for queue management follow */
int
create_event(THD *thd, Event_timed *et, bool check_existence);
create_event(THD *thd, Event_parse_data *et, bool check_existence);
int
update_event(THD *thd, Event_timed *et, LEX_STRING *new_schema,
LEX_STRING *new_name);
update_event(THD *thd, Event_parse_data *et, LEX_STRING *new_schema,
LEX_STRING *new_name);
bool
drop_event(THD *thd, sp_name *name);
......@@ -129,10 +129,7 @@ class Event_scheduler
private:
Event_timed *
find_event(Event_timed *etn, bool remove_from_q);
Event_timed *
find_event(sp_name *name, bool remove_from_q);
find_event(LEX_STRING db, LEX_STRING name, bool remove_from_q);
uint
workers_count();
......
......@@ -186,7 +186,7 @@ Events::reconstruct_interval_expression(String *buf, interval_type interval,
expr= tmp_expr - (tmp_expr/60)*60;
/* the code after the switch will finish */
}
break;
break;
case INTERVAL_DAY_SECOND:
{
ulonglong tmp_expr= expr;
......@@ -283,23 +283,19 @@ Events::open_event_table(THD *thd, enum thr_lock_type lock_type,
*/
int
Events::create_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
uint create_options, uint *rows_affected)
Events::create_event(THD *thd, Event_parse_data *parse_data, uint create_options,
uint *rows_affected)
{
int ret;
DBUG_ENTER("Events::create_event");
DBUG_PRINT("enter", ("name: %*s options:%d", et->name.length,
et->name.str, create_options));
if (!(ret= db_repository->
create_event(thd, et,
create_event(thd, parse_data,
create_options & HA_LEX_CREATE_IF_NOT_EXISTS,
rows_affected)))
{
Event_scheduler *scheduler= Event_scheduler::get_instance();
if (scheduler->initialized() &&
(ret= scheduler->create_event(thd, et, true)))
(ret= scheduler->create_event(thd, parse_data, true)))
my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
}
/* No need to close the table, it will be closed in sql_parse::do_command */
......@@ -315,7 +311,7 @@ Events::create_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
Events::update_event()
thd THD
et event's data
new_name set in case of RENAME TO.
new_name set in case of RENAME TO.
RETURN VALUE
0 OK
......@@ -328,25 +324,23 @@ Events::create_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
*/
int
Events::update_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
sp_name *new_name, uint *rows_affected)
Events::update_event(THD *thd, Event_parse_data *parse_data, sp_name *new_name,
uint *rows_affected)
{
int ret;
DBUG_ENTER("Events::update_event");
DBUG_PRINT("enter", ("name: %*s", et->name.length, et->name.str));
/*
db_update_event() opens & closes the table to prevent
crash later in the code when loading and compiling the new definition.
Also on error conditions my_error() is called so no need to handle here
*/
if (!(ret= db_repository->update_event(thd, et, new_name)))
if (!(ret= db_repository->update_event(thd, parse_data, new_name)))
{
Event_scheduler *scheduler= Event_scheduler::get_instance();
if (scheduler->initialized() &&
(ret= scheduler->update_event(thd, et,
new_name? &new_name->m_db: NULL,
new_name? &new_name->m_name: NULL)))
(ret= scheduler->update_event(thd, parse_data,
new_name? &new_name->m_db: NULL,
new_name? &new_name->m_name: NULL)))
my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
}
DBUG_RETURN(ret);
......@@ -411,7 +405,7 @@ Events::show_create_event(THD *thd, sp_name *spn)
DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str));
thd->reset_n_backup_open_tables_state(&backup);
ret= db_repository->find_event(thd, spn, &et, NULL, thd->mem_root);
ret= db_repository->find_event(thd, spn->m_db, spn->m_name, &et, NULL, thd->mem_root);
thd->restore_backup_open_tables_state(&backup);
if (!ret)
......
......@@ -17,7 +17,6 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
class sp_name;
class Event_timed;
class Event_parse_data;
class Event_db_repository;
......@@ -45,7 +44,6 @@ class Events
Event_timed::drop() and Event_timed is fixed not do drop directly
or other scheme will be found.
*/
friend class Event_timed;
static ulong opt_event_scheduler;
static TYPELIB opt_typelib;
......@@ -66,12 +64,12 @@ class Events
get_instance();
int
create_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
uint create_options, uint *rows_affected);
create_event(THD *thd, Event_parse_data *parse_data, uint create_options,
uint *rows_affected);
int
update_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
sp_name *new_name, uint *rows_affected);
update_event(THD *thd, Event_parse_data *parse_data, sp_name *new_name,
uint *rows_affected);
int
drop_event(THD *thd, sp_name *name, bool drop_if_exists, uint *rows_affected);
......
......@@ -174,11 +174,11 @@ void lex_start(THD *thd, const uchar *buf, uint length)
lex->sphead= NULL;
lex->spcont= NULL;
lex->proc_list.first= 0;
lex->escape_used= lex->et_compile_phase= FALSE;
lex->escape_used= FALSE;
lex->reset_query_tables_list(FALSE);
lex->name= 0;
lex->et= NULL;
lex->event_parse_data= NULL;
lex->nest_level=0 ;
lex->allow_sum_func= 0;
......
......@@ -27,7 +27,6 @@ class sp_instr;
class sp_pcontext;
class st_alter_tablespace;
class partition_info;
class Event_timed;
class Event_parse_data;
#ifdef MYSQL_SERVER
......@@ -1017,9 +1016,7 @@ typedef struct st_lex : public Query_tables_list
st_sp_chistics sp_chistics;
Event_timed *et;
Event_parse_data *event_parse_data;
bool et_compile_phase;
bool only_view; /* used for SHOW CREATE TABLE/VIEW */
/*
......
......@@ -3833,57 +3833,31 @@ mysql_execute_command(THD *thd)
case SQLCOM_ALTER_EVENT:
{
uint rows_affected= 1;
DBUG_ASSERT(lex->et);
do {
if (! lex->et->dbname.str ||
(lex->sql_command == SQLCOM_ALTER_EVENT && lex->spname &&
!lex->spname->m_db.str))
{
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
res= true;
break;
}
if (check_access(thd, EVENT_ACL, lex->et->dbname.str, 0, 0, 0,
is_schema_db(lex->et->dbname.str)) ||
(lex->sql_command == SQLCOM_ALTER_EVENT && lex->spname &&
(check_access(thd, EVENT_ACL, lex->spname->m_db.str, 0, 0, 0,
is_schema_db(lex->spname->m_db.str)))))
break;
if (end_active_trans(thd))
{
res= -1;
break;
}
switch (lex->sql_command) {
case SQLCOM_CREATE_EVENT:
res= Events::get_instance()->
create_event(thd, lex->et, lex->event_parse_data,
(uint) lex->create_info.options, &rows_affected);
break;
case SQLCOM_ALTER_EVENT:
res= Events::get_instance()->
update_event(thd, lex->et, lex->event_parse_data,
lex->spname, &rows_affected);
break;
default:;
}
DBUG_PRINT("info", ("CREATE/ALTER/DROP returned error code=%d af_rows=%d",
res, rows_affected));
if (!res)
send_ok(thd, rows_affected);
DBUG_ASSERT(lex->event_parse_data);
switch (lex->sql_command) {
case SQLCOM_CREATE_EVENT:
res= Events::get_instance()->create_event(thd, lex->event_parse_data,
(uint) lex->create_info.options,
&rows_affected);
break;
case SQLCOM_ALTER_EVENT:
res= Events::get_instance()->update_event(thd, lex->event_parse_data,
lex->spname, &rows_affected);
break;
default:;
}
DBUG_PRINT("info", ("CREATE/ALTER/DROP returned error code=%d af_rows=%d",
res, rows_affected));
if (!res)
send_ok(thd, rows_affected);
/* lex->unit.cleanup() is called outside, no need to call it here */
} while (0);
if (!thd->spcont)
{
lex->et->free_sphead_on_delete= true;
lex->et->free_sp();
lex->et->deinit_mutexes();
delete lex->sphead;
lex->sphead= NULL;
}
/* lex->unit.cleanup() is called outside, no need to call it here */
break;
}
case SQLCOM_DROP_EVENT:
......@@ -3912,11 +3886,6 @@ mysql_execute_command(THD *thd)
else
{
uint rows_affected= 1;
if (end_active_trans(thd))
{
res= -1;
break;
}
if (!(res= Events::get_instance()->drop_event(thd, lex->spname,
lex->drop_if_exists,
&rows_affected)))
......@@ -6020,14 +5989,6 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
{
delete lex->sphead;
lex->sphead= NULL;
if (lex->et)
{
lex->et->free_sphead_on_delete= true;
/* alloced on thd->mem_root so no real memory free but dtor call */
lex->et->free_sp();
lex->et->deinit_mutexes();
lex->et= NULL;
}
}
else
{
......@@ -6064,13 +6025,6 @@ void mysql_parse(THD *thd, char *inBuf, uint length)
delete lex->sphead;
lex->sphead= NULL;
}
if (lex->et)
{
lex->et->free_sphead_on_delete= true;
lex->et->free_sp();
lex->et->deinit_mutexes();
lex->et= NULL;
}
}
thd->proc_info="freeing items";
thd->end_statement();
......
......@@ -1290,24 +1290,11 @@ event_tail:
YYTHD->client_capabilities is set back to original value
*/
{
LEX *lex=Lex;
if (lex->et)
{
/*
Recursive CREATE EVENT statement are not possible because
recursive SPs are not also possible. lex->sp_head is not stacked.
*/
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "EVENT");
YYABORT;
}
lex->create_info.options= $2;
Lex->create_info.options= $2;
if (!(lex->et= new(YYTHD->mem_root) Event_timed())) // implicitly calls Event_timed::init()
YYABORT;
if (!(lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
if (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
YYABORT;
Lex->event_parse_data->identifier= $3;
/*
We have to turn of CLIENT_MULTI_QUERIES while parsing a
......@@ -1316,15 +1303,6 @@ event_tail:
*/
$<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES);
lex->event_parse_data->identifier= $3;
if (!lex->et_compile_phase)
{
lex->et->init_name(YYTHD, $3);
lex->et->init_definer(YYTHD);
}
}
ON SCHEDULE_SYM ev_schedule_time
opt_ev_on_completion
......@@ -1353,52 +1331,12 @@ ev_schedule_time: EVERY_SYM expr interval
{
Lex->event_parse_data->item_expression= $2;
Lex->event_parse_data->interval= $3;
LEX *lex=Lex;
if (!lex->et_compile_phase)
{
switch (lex->et->init_interval(YYTHD , $2, $3)) {
case EVEX_PARSE_ERROR:
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
break;
case EVEX_BAD_PARAMS:
my_error(ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG, MYF(0));
case EVEX_MICROSECOND_UNSUP:
my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND");
YYABORT;
break;
}
}
}
ev_starts
ev_ends
| AT_SYM expr
{
Lex->event_parse_data->item_execute_at= $2;
LEX *lex=Lex;
if (!lex->et_compile_phase)
{
switch (lex->et->init_execute_at(YYTHD, $2)) {
case EVEX_PARSE_ERROR:
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
break;
case ER_WRONG_VALUE:
{
char buff[120];
String str(buff,(uint32) sizeof(buff), system_charset_info);
String *str2= $2->val_str(&str);
my_error(ER_WRONG_VALUE, MYF(0), "AT",
str2? str2->c_ptr_safe():"NULL");
YYABORT;
break;
}
case EVEX_BAD_PARAMS:
my_error(ER_EVENT_EXEC_TIME_IN_THE_PAST, MYF(0));
YYABORT;
break;
}
}
}
;
......@@ -1406,18 +1344,11 @@ opt_ev_status: /* empty */ { $$= 0; }
| ENABLE_SYM
{
Lex->event_parse_data->status= Event_parse_data::ENABLED;
LEX *lex=Lex;
if (!lex->et_compile_phase)
lex->et->status= Event_timed::ENABLED;
$$= 1;
}
| DISABLE_SYM
{
Lex->event_parse_data->status= Event_parse_data::DISABLED;
LEX *lex=Lex;
if (!lex->et_compile_phase)
lex->et->status= Event_timed::DISABLED;
$$= 1;
}
;
......@@ -1425,32 +1356,10 @@ opt_ev_status: /* empty */ { $$= 0; }
ev_starts: /* empty */
{
Lex->event_parse_data->item_starts= new Item_func_now_local();
Lex->et->init_starts(YYTHD, new Item_func_now_local());
}
| STARTS_SYM expr
{
Lex->event_parse_data->item_starts= $2;
LEX *lex= Lex;
if (!lex->et_compile_phase)
{
switch (lex->et->init_starts(YYTHD, $2)) {
case EVEX_PARSE_ERROR:
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
break;
case EVEX_BAD_PARAMS:
{
char buff[20];
String str(buff,(uint32) sizeof(buff), system_charset_info);
String *str2= $2->val_str(&str);
my_error(ER_WRONG_VALUE, MYF(0), "STARTS",
str2 ? str2->c_ptr_safe() : NULL);
YYABORT;
break;
}
}
}
}
;
......@@ -1458,20 +1367,6 @@ ev_ends: /* empty */
| ENDS_SYM expr
{
Lex->event_parse_data->item_ends= $2;
LEX *lex= Lex;
if (!lex->et_compile_phase)
{
switch (lex->et->init_ends(YYTHD, $2)) {
case EVEX_PARSE_ERROR:
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
break;
case EVEX_BAD_PARAMS:
my_error(ER_EVENT_ENDS_BEFORE_STARTS, MYF(0));
YYABORT;
break;
}
}
}
;
......@@ -1484,18 +1379,12 @@ ev_on_completion:
{
Lex->event_parse_data->on_completion=
Event_parse_data::ON_COMPLETION_PRESERVE;
LEX *lex=Lex;
if (!lex->et_compile_phase)
lex->et->on_completion= Event_timed::ON_COMPLETION_PRESERVE;
$$= 1;
}
| ON COMPLETION_SYM NOT_SYM PRESERVE_SYM
{
Lex->event_parse_data->on_completion=
Event_parse_data::ON_COMPLETION_DROP;
LEX *lex=Lex;
if (!lex->et_compile_phase)
lex->et->on_completion= Event_timed::ON_COMPLETION_DROP;
$$= 1;
}
;
......@@ -1504,20 +1393,12 @@ opt_ev_comment: /* empty */ { $$= 0; }
| COMMENT_SYM TEXT_STRING_sys
{
Lex->comment= Lex->event_parse_data->comment= $2;
LEX *lex= Lex;
if (!lex->et_compile_phase)
{
lex->comment= $2;
lex->et->init_comment(YYTHD, &$2);
}
$$= 1;
}
;
ev_sql_stmt:
{
LEX *lex= Lex;
sp_head *sp;
/*
This stops the following :
......@@ -1557,8 +1438,6 @@ ev_sql_stmt:
Lex->event_parse_data->body_begin= lex->ptr;
if (!lex->et_compile_phase)
lex->et->body_begin= lex->ptr;
}
ev_sql_stmt_inner
{
......@@ -1570,14 +1449,7 @@ ev_sql_stmt:
lex->sp_chistics.suid= SP_IS_SUID;//always the definer!
lex->et->sphead= lex->sphead;
lex->sphead= NULL;
Lex->event_parse_data->init_body(YYTHD);
if (!lex->et_compile_phase)
{
lex->et->init_body(YYTHD);
}
}
;
......@@ -4753,25 +4625,12 @@ alter:
YYTHD->client_capabilities is set back to original value
*/
{
LEX *lex=Lex;
Event_timed *et;
lex->spname= NULL;
Lex->spname= NULL;
if (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
YYABORT;
Lex->event_parse_data->identifier= $3;
if (!(et= new (YYTHD->mem_root) Event_timed()))// implicitly calls Event_timed::init()
YYABORT;
lex->et = et;
if (!lex->et_compile_phase)
{
et->init_definer(YYTHD);
et->init_name(YYTHD, $3);
}
/*
We have to turn of CLIENT_MULTI_QUERIES while parsing a
stored procedure, otherwise yylex will chop it into pieces
......@@ -4838,7 +4697,7 @@ opt_ev_rename_to: /* empty */ { $$= 0;}
{
LEX *lex=Lex;
lex->spname= $3; //use lex's spname to hold the new name
//the original name is in the Event_timed object
//the original name is in the Event_parse_data object
$$= 1;
}
;
......
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