This commit is contained in:
andrey@lmy004. 2006-06-28 15:54:09 +02:00
commit f92454082a
30 changed files with 2055 additions and 1462 deletions

View File

@ -1778,3 +1778,8 @@ vio/viotest-sslconnect.cpp
vio/viotest.cpp
zlib/*.ds?
zlib/*.vcproj
libmysql/viosocket.o.6WmSJk
libmysqld/event_data_objects.cc
libmysqld/event_db_repository.cc
libmysqld/event_queue.cc
server-tools/instance-manager/net_serv.cc

View File

@ -68,7 +68,8 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
spatial.cc gstream.cc sql_help.cc tztime.cc sql_cursor.cc \
sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \
parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \
event_scheduler.cc events.cc event_timed.cc \
event_scheduler.cc events.cc event_data_objects.cc \
event_queue.cc event_db_repository.cc \
rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \
sql_tablespace.cc \
rpl_injector.cc my_user.c partition_info.cc

View File

@ -85,13 +85,25 @@ SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost RECURRING NULL 20 SECOND # # ENABLED
DROP EVENT event_starts_test;
create table test_nested(a int);
create event e_43 on schedule every 1 second do set @a = 5;
set global event_scheduler = 1;
alter event e_43 do alter event e_43 do set @a = 4;
ERROR HY000: Recursivity of EVENT DDL statements is forbidden when body is present
alter event e_43 do
begin
alter event e_43 on schedule every 5 minute;
insert into test_nested values(1);
end|
set global event_scheduler = 1;
select db, name, body, status, interval_field, interval_value from mysql.event;
db name body status interval_field interval_value
events_test e_43 set @a = 4 ENABLED SECOND 1
events_test e_43 begin
alter event e_43 on schedule every 5 minute;
insert into test_nested values(1);
end ENABLED MINUTE 5
drop event e_43;
drop table test_nested;
"Let's check whether we can use non-qualified names"
create table non_qualif(a int);
create event non_qualif_ev on schedule every 10 minute do insert into non_qualif values (800219);
@ -358,7 +370,7 @@ root localhost events_test Connect User lock select get_lock("test_lock2_1", 20)
drop event закачка21;
create table t_16 (s1 int);
create trigger t_16_bi before insert on t_16 for each row create event e_16 on schedule every 1 second do set @a=5;
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
ERROR HY000: Recursivity of EVENT DDL statements is forbidden when body is present
drop table t_16;
create event white_space
on schedule every 10 hour

View File

@ -17,18 +17,7 @@ DROP EVENT ДОЛЕН_регистър_утф8;
SET NAMES latin1;
set @a=3;
CREATE PROCEDURE p_16 () CREATE EVENT e_16 ON SCHEDULE EVERY @a SECOND DO SET @a=5;
call p_16();
"Here we used to crash!"
call p_16();
ERROR HY000: Event 'e_16' already exists
call p_16();
ERROR HY000: Event 'e_16' already exists
DROP EVENT e_16;
CALL p_16();
CALL p_16();
ERROR HY000: Event 'e_16' already exists
DROP PROCEDURE p_16;
DROP EVENT e_16;
ERROR HY000: Recursivity of EVENT DDL statements is forbidden when body is present
create event e_55 on schedule at 99990101000000 do drop table t;
ERROR HY000: Incorrect AT value: '99990101000000'
create event e_55 on schedule every 10 hour starts 99990101000000 do drop table t;

View File

@ -81,14 +81,23 @@ SHOW EVENTS;
DROP EVENT event_starts_test;
#
#
create table test_nested(a int);
create event e_43 on schedule every 1 second do set @a = 5;
set global event_scheduler = 1;
--sleep 2
--error 1562
alter event e_43 do alter event e_43 do set @a = 4;
--sleep 2
delimiter |;
alter event e_43 do
begin
alter event e_43 on schedule every 5 minute;
insert into test_nested values(1);
end|
delimiter ;|
set global event_scheduler = 1;
--sleep 1
select db, name, body, status, interval_field, interval_value from mysql.event;
drop event e_43;
--sleep 1
drop table test_nested;
--echo "Let's check whether we can use non-qualified names"
create table non_qualif(a int);
@ -315,7 +324,7 @@ drop event закачка21;
# Bug #16410 Events: CREATE EVENT is legal in a CREATE TRIGGER statement
#
create table t_16 (s1 int);
--error 1422
--error 1562
create trigger t_16_bi before insert on t_16 for each row create event e_16 on schedule every 1 second do set @a=5;
drop table t_16;
#

View File

@ -30,19 +30,8 @@ SET NAMES latin1;
# START - BUG#16408: Events: crash for an event in a procedure
#
set @a=3;
--error 1562
CREATE PROCEDURE p_16 () CREATE EVENT e_16 ON SCHEDULE EVERY @a SECOND DO SET @a=5;
call p_16();
--echo "Here we used to crash!"
--error ER_EVENT_ALREADY_EXISTS
call p_16();
--error ER_EVENT_ALREADY_EXISTS
call p_16();
DROP EVENT e_16;
CALL p_16();
--error ER_EVENT_ALREADY_EXISTS
CALL p_16();
DROP PROCEDURE p_16;
DROP EVENT e_16;
#
# END - BUG#16408: Events: crash for an event in a procedure
#

View File

@ -51,7 +51,8 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc
sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc
sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc
time.cc tztime.cc uniques.cc unireg.cc item_xmlfunc.cc
rpl_tblmap.cc sql_binlog.cc event_scheduler.cc event_timed.cc
rpl_tblmap.cc sql_binlog.cc event_scheduler.cc event_data_objects.cc
event_queue.cc event_db_repository.cc
sql_tablespace.cc events.cc ../sql-common/my_user.c
partition_info.cc rpl_injector.cc
${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc

View File

@ -64,8 +64,9 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
tztime.h my_decimal.h\
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
parse_file.h sql_view.h sql_trigger.h \
sql_array.h sql_cursor.h events.h events_priv.h \
sql_plugin.h authors.h sql_partition.h event_timed.h \
sql_array.h sql_cursor.h events.h \
sql_plugin.h authors.h sql_partition.h event_data_objects.h \
event_queue.h event_db_repository.h \
partition_info.h partition_element.h event_scheduler.h \
contributors.h
mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
@ -104,7 +105,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
tztime.cc my_time.c my_user.c my_decimal.cc\
sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
sp_cache.cc parse_file.cc sql_trigger.cc \
event_scheduler.cc events.cc event_timed.cc \
event_scheduler.cc events.cc event_data_objects.cc \
event_queue.cc event_db_repository.cc \
sql_plugin.cc sql_binlog.cc \
sql_builtin.cc sql_tablespace.cc partition_info.cc

View File

@ -16,12 +16,104 @@
#define MYSQL_LEX 1
#include "mysql_priv.h"
#include "events_priv.h"
#include "events.h"
#include "event_timed.h"
#include "event_data_objects.h"
#include "event_db_repository.h"
#include "sp_head.h"
#define EVEX_MAX_INTERVAL_VALUE 2147483647L
Event_parse_data *
Event_parse_data::new_instance(THD *thd)
{
return new (thd->mem_root) Event_parse_data;
}
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
@ -644,29 +736,29 @@ Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
et= this;
if (table->s->fields != Events::FIELD_COUNT)
if (table->s->fields != ET_FIELD_COUNT)
goto error;
if ((et->dbname.str= get_field(mem_root,
table->field[Events::FIELD_DB])) == NULL)
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[Events::FIELD_NAME])) == NULL)
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[Events::FIELD_BODY])) == NULL)
table->field[ET_FIELD_BODY])) == NULL)
goto error;
et->body.length= strlen(et->body.str);
if ((et->definer.str= get_field(mem_root,
table->field[Events::FIELD_DEFINER])) == NullS)
table->field[ET_FIELD_DEFINER])) == NullS)
goto error;
et->definer.length= strlen(et->definer.str);
@ -683,27 +775,27 @@ Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
et->definer_host.str= strmake_root(mem_root, ptr + 1, len);/* 1:because of @*/
et->definer_host.length= len;
et->starts_null= table->field[Events::FIELD_STARTS]->is_null();
res1= table->field[Events::FIELD_STARTS]->
et->starts_null= table->field[ET_FIELD_STARTS]->is_null();
res1= table->field[ET_FIELD_STARTS]->
get_date(&et->starts,TIME_NO_ZERO_DATE);
et->ends_null= table->field[Events::FIELD_ENDS]->is_null();
res2= table->field[Events::FIELD_ENDS]->get_date(&et->ends, TIME_NO_ZERO_DATE);
et->ends_null= table->field[ET_FIELD_ENDS]->is_null();
res2= table->field[ET_FIELD_ENDS]->get_date(&et->ends, TIME_NO_ZERO_DATE);
if (!table->field[Events::FIELD_INTERVAL_EXPR]->is_null())
et->expression= table->field[Events::FIELD_INTERVAL_EXPR]->val_int();
if (!table->field[ET_FIELD_INTERVAL_EXPR]->is_null())
et->expression= table->field[ET_FIELD_INTERVAL_EXPR]->val_int();
else
et->expression= 0;
/*
If res1 and res2 are true then both fields are empty.
Hence if Events::FIELD_EXECUTE_AT is empty there is an error.
Hence if ET_FIELD_EXECUTE_AT is empty there is an error.
*/
et->execute_at_null=
table->field[Events::FIELD_EXECUTE_AT]->is_null();
table->field[ET_FIELD_EXECUTE_AT]->is_null();
DBUG_ASSERT(!(et->starts_null && et->ends_null && !et->expression &&
et->execute_at_null));
if (!et->expression &&
table->field[Events::FIELD_EXECUTE_AT]-> get_date(&et->execute_at,
table->field[ET_FIELD_EXECUTE_AT]-> get_date(&et->execute_at,
TIME_NO_ZERO_DATE))
goto error;
@ -711,22 +803,22 @@ Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
In DB the values start from 1 but enum interval_type starts
from 0
*/
if (!table->field[Events::FIELD_TRANSIENT_INTERVAL]->is_null())
if (!table->field[ET_FIELD_TRANSIENT_INTERVAL]->is_null())
et->interval= (interval_type) ((ulonglong)
table->field[Events::FIELD_TRANSIENT_INTERVAL]->val_int() - 1);
table->field[ET_FIELD_TRANSIENT_INTERVAL]->val_int() - 1);
else
et->interval= (interval_type) 0;
et->created= table->field[Events::FIELD_CREATED]->val_int();
et->modified= table->field[Events::FIELD_MODIFIED]->val_int();
et->created= table->field[ET_FIELD_CREATED]->val_int();
et->modified= table->field[ET_FIELD_MODIFIED]->val_int();
table->field[Events::FIELD_LAST_EXECUTED]->
table->field[ET_FIELD_LAST_EXECUTED]->
get_date(&et->last_executed, TIME_NO_ZERO_DATE);
last_executed_changed= false;
/* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
if ((ptr= get_field(mem_root, table->field[Events::FIELD_STATUS])) == NullS)
if ((ptr= get_field(mem_root, table->field[ET_FIELD_STATUS])) == NullS)
goto error;
DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", et->name.str, ptr));
@ -734,20 +826,20 @@ Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
/* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
if ((ptr= get_field(mem_root,
table->field[Events::FIELD_ON_COMPLETION])) == NullS)
table->field[ET_FIELD_ON_COMPLETION])) == NullS)
goto error;
et->on_completion= (ptr[0]=='D'? Event_timed::ON_COMPLETION_DROP:
Event_timed::ON_COMPLETION_PRESERVE);
et->comment.str= get_field(mem_root, table->field[Events::FIELD_COMMENT]);
et->comment.str= get_field(mem_root, table->field[ET_FIELD_COMMENT]);
if (et->comment.str != NullS)
et->comment.length= strlen(et->comment.str);
else
et->comment.length= 0;
et->sql_mode= (ulong) table->field[Events::FIELD_SQL_MODE]->val_int();
et->sql_mode= (ulong) table->field[ET_FIELD_SQL_MODE]->val_int();
DBUG_RETURN(0);
error:
@ -1188,6 +1280,7 @@ Event_timed::mark_last_executed(THD *thd)
}
/*
Drops the event
@ -1210,7 +1303,8 @@ Event_timed::drop(THD *thd)
uint tmp= 0;
DBUG_ENTER("Event_timed::drop");
DBUG_RETURN(db_drop_event(thd, this, false, &tmp));
DBUG_RETURN(Events::get_instance()->
db_repository->drop_event(thd, dbname, name, false, &tmp));
}
@ -1247,7 +1341,7 @@ Event_timed::update_fields(THD *thd)
thd->reset_n_backup_open_tables_state(&backup);
if (Events::open_event_table(thd, TL_WRITE, &table))
if (Events::get_instance()->open_event_table(thd, TL_WRITE, &table))
{
ret= EVEX_OPEN_TABLE_FAILED;
goto done;
@ -1263,15 +1357,15 @@ Event_timed::update_fields(THD *thd)
if (last_executed_changed)
{
table->field[Events::FIELD_LAST_EXECUTED]->set_notnull();
table->field[Events::FIELD_LAST_EXECUTED]->store_time(&last_executed,
table->field[ET_FIELD_LAST_EXECUTED]->set_notnull();
table->field[ET_FIELD_LAST_EXECUTED]->store_time(&last_executed,
MYSQL_TIMESTAMP_DATETIME);
last_executed_changed= false;
}
if (status_changed)
{
table->field[Events::FIELD_STATUS]->set_notnull();
table->field[Events::FIELD_STATUS]->store((longlong)status, true);
table->field[ET_FIELD_STATUS]->set_notnull();
table->field[ET_FIELD_STATUS]->store((longlong)status, true);
status_changed= false;
}
@ -1541,8 +1635,8 @@ Event_timed::compile(THD *thd, MEM_ROOT *mem_root)
thd->query_length= show_create.length();
DBUG_PRINT("info", ("query:%s",thd->query));
change_security_context(thd, definer_user, definer_host, dbname,
&security_ctx, &save_ctx);
thd->change_security_context(definer_user, definer_host, dbname,
&security_ctx, &save_ctx);
thd->lex= &lex;
lex_start(thd, (uchar*)thd->query, thd->query_length);
lex.et_compile_phase= TRUE;
@ -1580,7 +1674,7 @@ done:
lex.et->deinit_mutexes();
lex_end(&lex);
restore_security_context(thd, save_ctx);
thd->restore_security_context(save_ctx);
DBUG_PRINT("note", ("return old data on its place. set back NAMES"));
thd->lex= old_lex;
@ -1781,23 +1875,6 @@ event_timed_db_equal(Event_timed *et, LEX_STRING *db)
}
/*
Checks whether two events have the same definer
SYNOPSIS
event_timed_definer_equal()
Returns
TRUE definers are equal
FALSE definers are not equal
*/
bool
event_timed_definer_equal(Event_timed *et, LEX_STRING *definer)
{
return !sortcmp_lex_string(et->definer, *definer, system_charset_info);
}
/*
Checks whether two events are equal by identifiers
@ -1814,8 +1891,62 @@ bool
event_timed_identifier_equal(Event_timed *a, Event_timed *b)
{
return event_timed_name_equal(a, &b->name) &&
event_timed_db_equal(a, &b->dbname) &&
event_timed_definer_equal(a, &b->definer);
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);
}

View File

@ -1,5 +1,5 @@
#ifndef _EVENT_TIMED_H_
#define _EVENT_TIMED_H_
#ifndef _EVENT_DATA_OBJECTS_H_
#define _EVENT_DATA_OBJECTS_H_
/* Copyright (C) 2004-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
@ -40,7 +40,34 @@
#define EVENT_FREE_WHEN_FINISHED (1L << 2)
#define EVENT_EXEC_STARTED 0
#define EVENT_EXEC_ALREADY_EXEC 1
#define EVENT_EXEC_CANT_FORK 2
class sp_head;
class Sql_alloc;
class Event_timed;
/* Compares only the schema part of the identifier */
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);
class Event_timed
{
@ -213,5 +240,92 @@ public:
void
set_thread_id(ulong tid) { thread_id= tid; }
};
#endif /* _EVENT_H_ */
class Event_parse_data : public Sql_alloc
{
Event_parse_data(const Event_parse_data &); /* Prevent use of these */
void operator=(Event_parse_data &);
public:
enum enum_status
{
ENABLED = 1,
DISABLED
};
enum enum_on_completion
{
ON_COMPLETION_DROP = 1,
ON_COMPLETION_PRESERVE
};
enum enum_on_completion on_completion;
enum enum_status status;
const uchar *body_begin;
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;
TIME starts;
TIME ends;
TIME execute_at;
my_bool starts_null;
my_bool ends_null;
my_bool execute_at_null;
sp_name *identifier;
Item* item_expression;
longlong expression;
interval_type interval;
static Event_parse_data *
new_instance(THD *thd);
Event_parse_data();
~Event_parse_data();
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);
};
class Event_queue_element : public Event_timed
{
};
#endif /* _EVENT_DATA_OBJECTS_H_ */

1038
sql/event_db_repository.cc Normal file

File diff suppressed because it is too large Load Diff

122
sql/event_db_repository.h Normal file
View File

@ -0,0 +1,122 @@
#ifndef _EVENT_DB_REPOSITORY_H_
#define _EVENT_DB_REPOSITORY_H_
/* Copyright (C) 2004-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
enum enum_events_table_field
{
ET_FIELD_DB = 0,
ET_FIELD_NAME,
ET_FIELD_BODY,
ET_FIELD_DEFINER,
ET_FIELD_EXECUTE_AT,
ET_FIELD_INTERVAL_EXPR,
ET_FIELD_TRANSIENT_INTERVAL,
ET_FIELD_CREATED,
ET_FIELD_MODIFIED,
ET_FIELD_LAST_EXECUTED,
ET_FIELD_STARTS,
ET_FIELD_ENDS,
ET_FIELD_STATUS,
ET_FIELD_ON_COMPLETION,
ET_FIELD_SQL_MODE,
ET_FIELD_COMMENT,
ET_FIELD_COUNT /* a cool trick to count the number of fields :) */
};
int
evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
const LEX_STRING ev_name,
TABLE *table);
int
events_table_index_read_for_db(THD *thd, TABLE *schema_table,
TABLE *event_table);
int
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_queue_element;
class Event_db_repository
{
public:
Event_db_repository(){}
~Event_db_repository(){}
int
init_repository();
void
deinit_repository();
int
create_event(THD *thd, Event_timed *et, my_bool create_if_not,
uint *rows_affected);
int
update_event(THD *thd, Event_timed *et, sp_name *new_name);
int
drop_event(THD *thd, LEX_STRING db, LEX_STRING name, bool drop_if_exists,
uint *rows_affected);
int
drop_schema_events(THD *thd, LEX_STRING schema);
int
drop_user_events(THD *thd, LEX_STRING definer);
int
find_event(THD *thd, sp_name *name, Event_timed **ett, TABLE *tbl,
MEM_ROOT *root);
int
load_named_event(THD *thd, Event_timed *etn, Event_timed **etn_new);
int
find_event_by_name(THD *thd, LEX_STRING db, LEX_STRING name, TABLE *table);
int
open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
int
fill_schema_events(THD *thd, TABLE_LIST *tables, char *db);
private:
int
drop_events_by_field(THD *thd, enum enum_events_table_field field,
LEX_STRING field_value);
int
index_read_for_db_for_i_s(THD *thd, TABLE *schema_table, TABLE *event_table,
char *db);
int
table_scan_all_for_i_s(THD *thd, TABLE *schema_table, TABLE *event_table);
MEM_ROOT repo_root;
/* Prevent use of these */
Event_db_repository(const Event_db_repository &);
void operator=(Event_db_repository &);
};
#endif /* _EVENT_DB_REPOSITORY_H_ */

19
sql/event_queue.cc Normal file
View File

@ -0,0 +1,19 @@
/* Copyright (C) 2004-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysql_priv.h"
#include "event_queue.h"
#include "event_data_objects.h"

20
sql/event_queue.h Normal file
View File

@ -0,0 +1,20 @@
#ifndef _EVENT_QUEUE_H_
#define _EVENT_QUEUE_H_
/* Copyright (C) 2004-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#endif /* _EVENT_QUEUE_H_ */

View File

@ -15,10 +15,10 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysql_priv.h"
#include "events_priv.h"
#include "events.h"
#include "event_timed.h"
#include "event_data_objects.h"
#include "event_scheduler.h"
#include "event_db_repository.h"
#include "sp_head.h"
/*
@ -574,8 +574,8 @@ event_worker_thread(void *arg)
to change the context before sending the signal. We are under
LOCK_scheduler_data being held by Event_scheduler::run() -> ::execute_top().
*/
change_security_context(thd, event->definer_user, event->definer_host,
event->dbname, &security_ctx, &save_ctx);
thd->change_security_context(event->definer_user, event->definer_host,
event->dbname, &security_ctx, &save_ctx);
DBUG_PRINT("info", ("master_access=%d db_access=%d",
thd->security_ctx->master_access, thd->security_ctx->db_access));
@ -687,7 +687,7 @@ Event_scheduler::get_instance()
*/
bool
Event_scheduler::init()
Event_scheduler::init(Event_db_repository *db_repo)
{
int i= 0;
bool ret= FALSE;
@ -695,6 +695,7 @@ Event_scheduler::init()
DBUG_PRINT("enter", ("this=%p", this));
LOCK_SCHEDULER_DATA();
db_repository= db_repo;
for (;i < COND_LAST; i++)
if (pthread_cond_init(&cond_vars[i], NULL))
{
@ -783,10 +784,10 @@ Event_scheduler::destroy()
OP_LOAD_ERROR Error during loading from disk
*/
enum Event_scheduler::enum_error_code
int
Event_scheduler::create_event(THD *thd, Event_timed *et, bool check_existence)
{
enum enum_error_code res;
int res;
Event_timed *et_new;
DBUG_ENTER("Event_scheduler::create_event");
DBUG_PRINT("enter", ("thd=%p et=%p lock=%p",thd,et,&LOCK_scheduler_data));
@ -805,7 +806,7 @@ Event_scheduler::create_event(THD *thd, Event_timed *et, bool check_existence)
}
/* We need to load the event on scheduler_root */
if (!(res= load_named_event(thd, et, &et_new)))
if (!(res= db_repository->load_named_event(thd, et, &et_new)))
{
queue_insert_safe(&queue, (byte *) et_new);
DBUG_PRINT("info", ("Sending COND_new_work"));
@ -833,12 +834,13 @@ end:
*/
bool
Event_scheduler::drop_event(THD *thd, Event_timed *et)
Event_scheduler::drop_event(THD *thd, sp_name *name)
{
int res;
Event_timed *et_old;
DBUG_ENTER("Event_scheduler::drop_event");
DBUG_PRINT("enter", ("thd=%p et=%p lock=%p",thd,et,&LOCK_scheduler_data));
DBUG_PRINT("enter", ("thd=%p name=%p lock=%p", thd, name,
&LOCK_scheduler_data));
LOCK_SCHEDULER_DATA();
if (!is_running_or_suspended())
@ -848,7 +850,7 @@ Event_scheduler::drop_event(THD *thd, Event_timed *et)
DBUG_RETURN(OP_OK);
}
if (!(et_old= find_event(et, TRUE)))
if (!(et_old= find_event(name, TRUE)))
DBUG_PRINT("info", ("No such event found, probably DISABLED"));
UNLOCK_SCHEDULER_DATA();
@ -903,12 +905,12 @@ Event_scheduler::drop_event(THD *thd, Event_timed *et)
OP_ALREADY_EXISTS Event already in the queue
*/
enum Event_scheduler::enum_error_code
int
Event_scheduler::update_event(THD *thd, Event_timed *et,
LEX_STRING *new_schema,
LEX_STRING *new_name)
{
enum enum_error_code res;
int res= OP_OK;
Event_timed *et_old, *et_new= NULL;
LEX_STRING old_schema, old_name;
@ -946,7 +948,7 @@ 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= load_named_event(thd, et, &et_new)))
if (!(res= db_repository->load_named_event(thd, et, &et_new)))
{
queue_insert_safe(&queue, (byte *) et_new);
DBUG_PRINT("info", ("Sending COND_new_work"));
@ -960,7 +962,7 @@ Event_scheduler::update_event(THD *thd, Event_timed *et,
et->dbname= old_schema;
et->name= old_name;
}
DBUG_PRINT("info", ("res=%d", res));
UNLOCK_SCHEDULER_DATA();
/*
Andrey: Is this comment still truthful ???
@ -1049,6 +1051,48 @@ Event_scheduler::find_event(Event_timed *etn, bool remove_from_q)
}
/*
Searches for an event in the scheduler queue
SYNOPSIS
Event_scheduler::find_event()
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
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(sp_name *name, 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]?", name->m_db.str, name->m_name.str,
et->dbname.str, et->name.str));
if (event_timed_identifier_equal(name, et))
{
if (remove_from_q)
queue_remove(&queue, i);
DBUG_RETURN(et);
}
}
DBUG_RETURN(NULL);
}
/*
Drops all events from the in-memory queue and disk that match
certain pattern evaluated by a comparator function
@ -1068,11 +1112,11 @@ Event_scheduler::find_event(Event_timed *etn, bool remove_from_q)
*/
void
Event_scheduler::drop_matching_events(THD *thd, LEX_STRING *pattern,
Event_scheduler::drop_matching_events(THD *thd, LEX_STRING pattern,
bool (*comparator)(Event_timed *,LEX_STRING *))
{
DBUG_ENTER("Event_scheduler::drop_matching_events");
DBUG_PRINT("enter", ("pattern=%*s state=%d", pattern->length, pattern->str,
DBUG_PRINT("enter", ("pattern=%*s state=%d", pattern.length, pattern.str,
state));
if (is_running_or_suspended())
{
@ -1081,7 +1125,7 @@ Event_scheduler::drop_matching_events(THD *thd, LEX_STRING *pattern,
{
Event_timed *et= (Event_timed *) queue_element(&queue, i);
DBUG_PRINT("info", ("[%s.%s]?", et->dbname.str, et->name.str));
if (comparator(et, pattern))
if (comparator(et, &pattern))
{
/*
The queue is ordered. If we remove an element, then all elements after
@ -1136,7 +1180,7 @@ Event_scheduler::drop_matching_events(THD *thd, LEX_STRING *pattern,
*/
int
Event_scheduler::drop_schema_events(THD *thd, LEX_STRING *schema)
Event_scheduler::drop_schema_events(THD *thd, LEX_STRING schema)
{
int ret;
DBUG_ENTER("Event_scheduler::drop_schema_events");
@ -1144,7 +1188,6 @@ Event_scheduler::drop_schema_events(THD *thd, LEX_STRING *schema)
if (is_running_or_suspended())
drop_matching_events(thd, schema, event_timed_db_equal);
ret= db_drop_events_from_table(thd, schema);
UNLOCK_SCHEDULER_DATA();
DBUG_RETURN(ret);
@ -1670,7 +1713,7 @@ Event_scheduler::stop_all_running_events(THD *thd)
The caller must have acquited LOCK_scheduler_data.
*/
enum Event_scheduler::enum_error_code
int
Event_scheduler::stop()
{
THD *thd= current_thd;
@ -1735,7 +1778,7 @@ Event_scheduler::stop()
OP_OK OK
*/
enum Event_scheduler::enum_error_code
int
Event_scheduler::suspend_or_resume(
enum Event_scheduler::enum_suspend_or_resume action)
{
@ -2073,59 +2116,6 @@ Event_scheduler::events_count()
}
/*
Looks for a named event in mysql.event and then loads it from
the table, compiles and inserts it into the cache.
SYNOPSIS
Event_scheduler::load_named_event()
thd THD
etn The name of the event to load and compile on scheduler's root
etn_new The loaded event
RETURN VALUE
NULL Error during compile or the event is non-enabled.
otherwise Address
*/
enum Event_scheduler::enum_error_code
Event_scheduler::load_named_event(THD *thd, Event_timed *etn, Event_timed **etn_new)
{
int ret= 0;
MEM_ROOT *tmp_mem_root;
Event_timed *et_loaded= NULL;
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));
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= db_find_event(thd, &spn, &et_loaded, NULL, &scheduler_root);
}
thd->restore_backup_open_tables_state(&backup);
/* In this case no memory was allocated so we don't need to clean */
if (ret)
DBUG_RETURN(OP_LOAD_ERROR);
if (et_loaded->status != Event_timed::ENABLED)
{
/*
We don't load non-enabled events.
In db_find_event() `et_new` was allocated on the heap and not on
scheduler_root therefore we delete it here.
*/
delete et_loaded;
DBUG_RETURN(OP_DISABLED_EVENT);
}
et_loaded->compute_next_execution_time();
*etn_new= et_loaded;
DBUG_RETURN(OP_OK);
}
/*
@ -2169,7 +2159,7 @@ Event_scheduler::load_events_from_db(THD *thd)
DBUG_RETURN(EVEX_GENERAL_ERROR);
}
if ((ret= Events::open_event_table(thd, TL_READ, &table)))
if ((ret= db_repository->open_event_table(thd, TL_READ, &table)))
{
sql_print_error("SCHEDULER: Table mysql.event is damaged. Can not open.");
DBUG_RETURN(EVEX_OPEN_TABLE_FAILED);

View File

@ -16,7 +16,9 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
class sp_name;
class Event_timed;
class Event_db_repository;
class THD;
typedef bool * (*event_timed_identifier_comparator)(Event_timed*, Event_timed*);
@ -30,17 +32,6 @@ events_shutdown();
class Event_scheduler
{
public:
/* Return codes */
enum enum_error_code
{
OP_OK= 0,
OP_NOT_RUNNING,
OP_CANT_KILL,
OP_CANT_INIT,
OP_DISABLED_EVENT,
OP_LOAD_ERROR,
OP_ALREADY_EXISTS
};
enum enum_state
{
@ -65,22 +56,22 @@ public:
/* Methods for queue management follow */
enum enum_error_code
int
create_event(THD *thd, Event_timed *et, bool check_existence);
enum enum_error_code
int
update_event(THD *thd, Event_timed *et, LEX_STRING *new_schema,
LEX_STRING *new_name);
bool
drop_event(THD *thd, Event_timed *et);
drop_event(THD *thd, sp_name *name);
int
drop_schema_events(THD *thd, LEX_STRING *schema);
drop_schema_events(THD *thd, LEX_STRING schema);
int
drop_user_events(THD *thd, LEX_STRING *definer, uint *dropped_num)
drop_user_events(THD *thd, LEX_STRING *definer)
{ DBUG_ASSERT(0); return 0;}
uint
@ -91,20 +82,24 @@ public:
bool
start();
enum enum_error_code
int
stop();
bool
start_suspended();
/*
Need to be public because has to be called from the function
passed to pthread_create.
*/
bool
run(THD *thd);
enum enum_error_code
int
suspend_or_resume(enum enum_suspend_or_resume action);
bool
init();
init(Event_db_repository *db_repo);
void
destroy();
@ -136,6 +131,9 @@ private:
Event_timed *
find_event(Event_timed *etn, bool remove_from_q);
Event_timed *
find_event(sp_name *name, bool remove_from_q);
uint
workers_count();
@ -152,14 +150,11 @@ private:
void
stop_all_running_events(THD *thd);
enum enum_error_code
load_named_event(THD *thd, Event_timed *etn, Event_timed **etn_new);
int
load_events_from_db(THD *thd);
void
drop_matching_events(THD *thd, LEX_STRING *pattern,
drop_matching_events(THD *thd, LEX_STRING pattern,
bool (*)(Event_timed *,LEX_STRING *));
bool
@ -226,6 +221,8 @@ private:
/* The MEM_ROOT of the object */
MEM_ROOT scheduler_root;
Event_db_repository *db_repository;
/* The sorted queue with the Event_timed objects */
QUEUE queue;

File diff suppressed because it is too large Load Diff

View File

@ -16,78 +16,96 @@
along with this program; if not, write to the Free Software
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;
/* Return codes */
enum enum_events_error_code
{
OP_OK= 0,
OP_NOT_RUNNING,
OP_CANT_KILL,
OP_CANT_INIT,
OP_DISABLED_EVENT,
OP_LOAD_ERROR,
OP_ALREADY_EXISTS
};
int
sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
class Events
{
public:
/*
Quite NOT the best practice and will be removed once
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;
enum enum_table_field
{
FIELD_DB = 0,
FIELD_NAME,
FIELD_BODY,
FIELD_DEFINER,
FIELD_EXECUTE_AT,
FIELD_INTERVAL_EXPR,
FIELD_TRANSIENT_INTERVAL,
FIELD_CREATED,
FIELD_MODIFIED,
FIELD_LAST_EXECUTED,
FIELD_STARTS,
FIELD_ENDS,
FIELD_STATUS,
FIELD_ON_COMPLETION,
FIELD_SQL_MODE,
FIELD_COMMENT,
FIELD_COUNT /* a cool trick to count the number of fields :) */
};
int
init();
void
deinit();
static int
create_event(THD *thd, Event_timed *et, uint create_options,
uint *rows_affected);
void
init_mutexes();
void
destroy_mutexes();
static int
update_event(THD *thd, Event_timed *et, sp_name *new_name,
uint *rows_affected);
static Events*
get_instance();
static int
drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
uint *rows_affected);
int
create_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
uint create_options, uint *rows_affected);
static int
int
update_event(THD *thd, Event_timed *et, 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);
int
drop_schema_events(THD *thd, char *db);
int
open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
static int
int
show_create_event(THD *thd, sp_name *spn);
/* Needed for both SHOW CREATE EVENT and INFORMATION_SCHEMA */
static int
reconstruct_interval_expression(String *buf, interval_type interval,
longlong expression);
static int
drop_schema_events(THD *thd, char *db);
fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */);
static int
int
dump_internal_status(THD *thd);
static int
init();
static void
shutdown();
static void
init_mutexes();
static void
destroy_mutexes();
Event_db_repository *db_repository;
private:
/* Singleton DP is used */
Events(){}
~Events(){}
/* Singleton instance */
static Events singleton;
/* Prevent use of these */
Events(const Events &);
void operator=(Events &);

View File

@ -1,79 +0,0 @@
#ifndef _EVENT_PRIV_H_
#define _EVENT_PRIV_H_
/* Copyright (C) 2004-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#define EVENT_EXEC_STARTED 0
#define EVENT_EXEC_ALREADY_EXEC 1
#define EVENT_EXEC_CANT_FORK 2
#define EVEX_DB_FIELD_LEN 64
#define EVEX_NAME_FIELD_LEN 64
#define EVEX_MAX_INTERVAL_VALUE 2147483647L
class Event_timed;
int
evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
const LEX_STRING ev_name,
TABLE *table);
int
db_drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
uint *rows_affected);
int
db_find_event(THD *thd, sp_name *name, Event_timed **ett, TABLE *tbl,
MEM_ROOT *root);
int
db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
uint *rows_affected);
int
db_drop_events_from_table(THD *thd, LEX_STRING *db);
int
sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
/* Compares only the name part of the identifier */
bool
event_timed_name_equal(Event_timed *et, LEX_STRING *name);
/* Compares only the schema part of the identifier */
bool
event_timed_db_equal(Event_timed *et, LEX_STRING *db);
/*
Compares only the definer part of the identifier. Use during DROP USER
to drop user's events. (Still not implemented)
*/
bool
event_timed_definer_equal(Event_timed *et, LEX_STRING *definer);
/* Compares the whole identifier*/
bool
event_timed_identifier_equal(Event_timed *a, Event_timed *b);
bool
change_security_context(THD *thd, LEX_STRING user, LEX_STRING host,
LEX_STRING db, Security_context *s_ctx,
Security_context **backup);
void
restore_security_context(THD *thd, Security_context *backup);
#endif /* _EVENT_PRIV_H_ */

View File

@ -883,7 +883,7 @@ static void close_connections(void)
}
(void) pthread_mutex_unlock(&LOCK_thread_count); // For unlink from list
Events::shutdown();
Events::get_instance()->deinit();
end_slave();
if (thread_count)
@ -1321,7 +1321,7 @@ static void clean_up_mutexes()
(void) pthread_mutex_destroy(&LOCK_bytes_sent);
(void) pthread_mutex_destroy(&LOCK_bytes_received);
(void) pthread_mutex_destroy(&LOCK_user_conn);
Events::destroy_mutexes();
Events::get_instance()->destroy_mutexes();
#ifdef HAVE_OPENSSL
(void) pthread_mutex_destroy(&LOCK_des_key_file);
#ifndef HAVE_YASSL
@ -2884,7 +2884,7 @@ static int init_thread_environment()
(void) pthread_mutex_init(&LOCK_server_started, MY_MUTEX_INIT_FAST);
(void) pthread_cond_init(&COND_server_started,NULL);
sp_cache_init();
Events::init_mutexes();
Events::get_instance()->init_mutexes();
/* Parameter for threads created for connections */
(void) pthread_attr_init(&connection_attrib);
(void) pthread_attr_setdetachstate(&connection_attrib,
@ -3673,7 +3673,7 @@ we force server id to 2, but this MySQL server will not act as a slave.");
if (!opt_noacl)
{
Events::init();
Events::get_instance()->init();
}
#if defined(__NT__) || defined(HAVE_SMEM)
handle_connections_methods();

View File

@ -3892,7 +3892,7 @@ byte *sys_var_thd_dbug::value_ptr(THD *thd, enum_var_type type, LEX_STRING *b)
bool
sys_var_event_scheduler::update(THD *thd, set_var *var)
{
enum Event_scheduler::enum_error_code res;
int res;
Event_scheduler *scheduler= Event_scheduler::get_instance();
/* here start the thread if not running. */
DBUG_ENTER("sys_var_event_scheduler::update");

View File

@ -5839,3 +5839,6 @@ ER_CANT_ACTIVATE_LOG
eng "Cannot activate '%-.64s' log."
ER_RBR_NOT_AVAILABLE
eng "The server was not built with row-based replication"
ER_EVENT_RECURSIVITY_FORBIDDEN
eng "Recursivity of EVENT DDL statements is forbidden when body is present"

View File

@ -2073,6 +2073,63 @@ bool Security_context::set_user(char *user_arg)
return user == 0;
}
/*
Switches the security context
SYNOPSIS
THD::change_security_context()
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
FALSE OK
TRUE Error (generates error too)
*/
bool
THD::change_security_context(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= security_ctx;
security_ctx= s_ctx;
#endif
DBUG_RETURN(FALSE);
}
/*
Restores the security context
SYNOPSIS
restore_security_context()
thd Thread
backup Context to switch to
*/
void
THD::restore_security_context(Security_context *backup)
{
DBUG_ENTER("restore_security_context");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (backup)
security_ctx= backup;
#endif
DBUG_VOID_RETURN;
}
/****************************************************************************
Handling of open and locked tables states.

View File

@ -868,6 +868,14 @@ public:
char *db, *catalog;
Security_context main_security_ctx;
Security_context *security_ctx;
bool
change_security_context(LEX_STRING user, LEX_STRING host,
LEX_STRING db, Security_context *s_ctx,
Security_context **backup);
void
restore_security_context(Security_context *backup);
/* remote (peer) port */
uint16 peer_port;

View File

@ -904,7 +904,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
exit:
(void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */
error= Events::drop_schema_events(thd, db);
error= Events::get_instance()->drop_schema_events(thd, db);
/*
If this database was the client's selected database, we silently change the
client's selected database to nothing (to have an empty SELECT DATABASE()

View File

@ -28,6 +28,7 @@ class sp_pcontext;
class st_alter_tablespace;
class partition_info;
class Event_timed;
class Event_parse_data;
#ifdef MYSQL_SERVER
/*
@ -1017,6 +1018,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 */

View File

@ -27,7 +27,7 @@
#include "sp.h"
#include "sp_cache.h"
#include "events.h"
#include "event_timed.h"
#include "event_data_objects.h"
#ifdef HAVE_OPENSSL
/*
@ -3831,7 +3831,6 @@ end_with_restore_list:
}
case SQLCOM_CREATE_EVENT:
case SQLCOM_ALTER_EVENT:
case SQLCOM_DROP_EVENT:
{
uint rows_affected= 1;
DBUG_ASSERT(lex->et);
@ -3860,17 +3859,15 @@ end_with_restore_list:
switch (lex->sql_command) {
case SQLCOM_CREATE_EVENT:
res= Events::create_event(thd, lex->et,
(uint) lex->create_info.options,
&rows_affected);
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::update_event(thd, lex->et, lex->spname,
&rows_affected);
res= Events::get_instance()->
update_event(thd, lex->et, lex->event_parse_data,
lex->spname, &rows_affected);
break;
case SQLCOM_DROP_EVENT:
res= Events::drop_event(thd, lex->et, lex->drop_if_exists,
&rows_affected);
default:;
}
DBUG_PRINT("info", ("CREATE/ALTER/DROP returned error code=%d af_rows=%d",
@ -3889,10 +3886,10 @@ end_with_restore_list:
break;
}
case SQLCOM_DROP_EVENT:
case SQLCOM_SHOW_CREATE_EVENT:
{
DBUG_ASSERT(lex->spname);
DBUG_ASSERT(lex->et);
if (! lex->spname->m_db.str)
{
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
@ -3906,15 +3903,31 @@ end_with_restore_list:
if (lex->spname->m_name.length > NAME_LEN)
{
my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
/* this jumps to the end of the function and skips own messaging */
goto error;
}
res= Events::show_create_event(thd, lex->spname);
if (lex->sql_command == SQLCOM_SHOW_CREATE_EVENT)
res= Events::get_instance()->show_create_event(thd, lex->spname);
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)))
send_ok(thd, rows_affected);
}
break;
}
#ifndef DBUG_OFF
case SQLCOM_SHOW_SCHEDULER_STATUS:
{
res= Events::dump_internal_status(thd);
res= Events::get_instance()->dump_internal_status(thd);
break;
}
#endif

View File

@ -27,7 +27,7 @@
#include "authors.h"
#include "contributors.h"
#include "events.h"
#include "event_timed.h"
#include "event_data_objects.h"
#include <my_dir.h>
#ifdef WITH_PARTITION_STORAGE_ENGINE
@ -4166,7 +4166,7 @@ extern LEX_STRING interval_type_to_name[];
1 Error
*/
static int
int
copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
{
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
@ -4301,183 +4301,6 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
}
/*
Performs an index scan of event_table (mysql.event) and fills schema_table.
Synopsis
events_table_index_read_for_db()
thd Thread
schema_table The I_S.EVENTS table
event_table The event table to use for loading (mysql.event)
Returns
0 OK
1 Error
*/
static
int events_table_index_read_for_db(THD *thd, TABLE *schema_table,
TABLE *event_table)
{
int ret=0;
CHARSET_INFO *scs= system_charset_info;
KEY *key_info;
uint key_len;
byte *key_buf= NULL;
LINT_INIT(key_buf);
DBUG_ENTER("schema_events_do_index_scan");
DBUG_PRINT("info", ("Using prefix scanning on PK"));
event_table->file->ha_index_init(0, 1);
event_table->field[Events::FIELD_DB]->
store(thd->lex->select_lex.db, strlen(thd->lex->select_lex.db), scs);
key_info= event_table->key_info;
key_len= key_info->key_part[0].store_length;
if (!(key_buf= (byte *)alloc_root(thd->mem_root, key_len)))
{
ret= 1;
/* don't send error, it would be done by sql_alloc_error_handler() */
}
else
{
key_copy(key_buf, event_table->record[0], key_info, key_len);
if (!(ret= event_table->file->index_read(event_table->record[0], key_buf,
key_len, HA_READ_PREFIX)))
{
DBUG_PRINT("info",("Found rows. Let's retrieve them. ret=%d", ret));
do
{
ret= copy_event_to_schema_table(thd, schema_table, event_table);
if (ret == 0)
ret= event_table->file->index_next_same(event_table->record[0],
key_buf, key_len);
} while (ret == 0);
}
DBUG_PRINT("info", ("Scan finished. ret=%d", ret));
}
event_table->file->ha_index_end();
/* ret is guaranteed to be != 0 */
if (ret == HA_ERR_END_OF_FILE || ret == HA_ERR_KEY_NOT_FOUND)
DBUG_RETURN(0);
DBUG_RETURN(1);
}
/*
Performs a table scan of event_table (mysql.event) and fills schema_table.
Synopsis
events_table_scan_all()
thd Thread
schema_table The I_S.EVENTS in memory table
event_table The event table to use for loading.
Returns
0 OK
1 Error
*/
static
int events_table_scan_all(THD *thd, TABLE *schema_table,
TABLE *event_table)
{
int ret;
READ_RECORD read_record_info;
DBUG_ENTER("schema_events_do_table_scan");
init_read_record(&read_record_info, thd, event_table, NULL, 1, 0);
/*
rr_sequential, in read_record(), returns 137==HA_ERR_END_OF_FILE,
but rr_handle_error returns -1 for that reason. Thus, read_record()
returns -1 eventually.
*/
do
{
ret= read_record_info.read_record(&read_record_info);
if (ret == 0)
ret= copy_event_to_schema_table(thd, schema_table, event_table);
}
while (ret == 0);
DBUG_PRINT("info", ("Scan finished. ret=%d", ret));
end_read_record(&read_record_info);
/* ret is guaranteed to be != 0 */
DBUG_RETURN(ret == -1? 0:1);
}
/*
Fills I_S.EVENTS with data loaded from mysql.event. Also used by
SHOW EVENTS
Synopsis
fill_schema_events()
thd Thread
tables The schema table
cond Unused
Returns
0 OK
1 Error
*/
int fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
{
TABLE *schema_table= tables->table;
TABLE *event_table= NULL;
Open_tables_state backup;
int ret= 0;
DBUG_ENTER("fill_schema_events");
/*
If it's SHOW EVENTS then thd->lex->select_lex.db is guaranteed not to
be NULL. Let's do an assert anyway.
*/
if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS)
{
DBUG_ASSERT(thd->lex->select_lex.db);
if (check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0,
is_schema_db(thd->lex->select_lex.db)))
DBUG_RETURN(1);
}
DBUG_PRINT("info",("db=%s", thd->lex->select_lex.db?
thd->lex->select_lex.db:"(null)"));
thd->reset_n_backup_open_tables_state(&backup);
if (Events::open_event_table(thd, TL_READ, &event_table))
{
sql_print_error("Table mysql.event is damaged.");
thd->restore_backup_open_tables_state(&backup);
DBUG_RETURN(1);
}
/*
1. SELECT I_S => use table scan. I_S.EVENTS does not guarantee order
thus we won't order it. OTOH, SHOW EVENTS will be
ordered.
2. SHOW EVENTS => PRIMARY KEY with prefix scanning on (db)
Reasoning: Events are per schema, therefore a scan over an index
will save use from doing a table scan and comparing
every single row's `db` with the schema which we show.
*/
if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS)
ret= events_table_index_read_for_db(thd, schema_table, event_table);
else
ret= events_table_scan_all(thd, schema_table, event_table);
close_thread_tables(thd);
thd->restore_backup_open_tables_state(&backup);
DBUG_PRINT("info", ("Return code=%d", ret));
DBUG_RETURN(ret);
}
int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
DBUG_ENTER("fill_open_tables");
@ -5574,7 +5397,7 @@ ST_SCHEMA_TABLE schema_tables[]=
{"ENGINES", engines_fields_info, create_schema_table,
fill_schema_engines, make_old_format, 0, -1, -1, 0},
{"EVENTS", events_fields_info, create_schema_table,
fill_schema_events, make_old_format, 0, -1, -1, 0},
Events::fill_schema_events, make_old_format, 0, -1, -1, 0},
{"FILES", files_fields_info, create_schema_table,
fill_schema_files, 0, 0, -1, -1, 0},
{"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table,

View File

@ -14,4 +14,6 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
HA_CREATE_INFO *create_info_arg);
int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff);
int copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table);
#endif /* SQL_SHOW_H */

View File

@ -38,7 +38,7 @@
#include "sp_pcontext.h"
#include "sp_rcontext.h"
#include "sp.h"
#include "event_timed.h"
#include "event_data_objects.h"
#include <myisam.h>
#include <myisammrg.h>
@ -880,7 +880,8 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
sp_c_chistics sp_a_chistics sp_chistic sp_c_chistic xa
load_data opt_field_or_var_spec fields_or_vars opt_load_data_set_spec
definer view_replace_or_algorithm view_replace view_algorithm_opt
view_algorithm view_or_trigger_or_sp view_or_trigger_or_sp_tail
view_algorithm view_or_trigger_or_sp_or_event
view_or_trigger_or_sp_or_event_tail
view_suid view_tail view_list_opt view_list view_select
view_check_option trigger_tail sp_tail
install uninstall partition_entry binlog_base64_event
@ -1257,73 +1258,13 @@ create:
lex->name=$4.str;
lex->create_info.options=$3;
}
| CREATE EVENT_SYM opt_if_not_exists sp_name
/*
BE CAREFUL when you add a new rule to update the block where
YYTHD->client_capabilities is set back to original value
*/
{
LEX *lex=Lex;
if (lex->et)
{
/*
Recursive events are not possible because recursive SPs
are not also possible. lex->sp_head is not stacked.
*/
// ToDo Andrey : Change the error message
my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "EVENT");
YYABORT;
}
lex->create_info.options= $3;
if (!(lex->et= new(YYTHD->mem_root) Event_timed())) // implicitly calls Event_timed::init()
YYABORT;
/*
We have to turn of CLIENT_MULTI_QUERIES while parsing a
stored procedure, otherwise yylex will chop it into pieces
at each ';'.
*/
$<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES);
if (!lex->et_compile_phase)
{
lex->et->init_name(YYTHD, $4);
lex->et->init_definer(YYTHD);
}
}
ON SCHEDULE_SYM ev_schedule_time
opt_ev_on_completion
opt_ev_status
opt_ev_comment
DO_SYM ev_sql_stmt
{
/*
Restore flag if it was cleared above
$1 - CREATE
$2 - EVENT_SYM
$3 - opt_if_not_exists
$4 - sp_name
$5 - the block above
*/
YYTHD->client_capabilities |= $<ulong_num>5;
/*
sql_command is set here because some rules in ev_sql_stmt
can overwrite it
*/
Lex->sql_command= SQLCOM_CREATE_EVENT;
}
| CREATE
{
Lex->create_view_mode= VIEW_CREATE_NEW;
Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED;
Lex->create_view_suid= TRUE;
}
view_or_trigger_or_sp
view_or_trigger_or_sp_or_event
{}
| CREATE USER clear_privileges grant_list
{
@ -1342,8 +1283,76 @@ create:
;
event_tail:
EVENT_SYM opt_if_not_exists sp_name
/*
BE CAREFUL when you add a new rule to update the block where
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;
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)))
YYABORT;
/*
We have to turn of CLIENT_MULTI_QUERIES while parsing a
stored procedure, otherwise yylex will chop it into pieces
at each ';'.
*/
$<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
opt_ev_status
opt_ev_comment
DO_SYM ev_sql_stmt
{
/*
Restore flag if it was cleared above
$1 - EVENT_SYM
$2 - opt_if_not_exists
$3 - sp_name
$4 - the block above
*/
YYTHD->client_capabilities |= $<ulong_num>4;
/*
sql_command is set here because some rules in ev_sql_stmt
can overwrite it
*/
Lex->sql_command= SQLCOM_CREATE_EVENT;
}
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)
{
@ -1365,6 +1374,7 @@ ev_schedule_time: EVERY_SYM expr interval
ev_ends
| AT_SYM expr
{
Lex->event_parse_data->item_execute_at= $2;
LEX *lex=Lex;
if (!lex->et_compile_phase)
{
@ -1395,6 +1405,7 @@ ev_schedule_time: EVERY_SYM expr interval
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;
@ -1402,6 +1413,7 @@ opt_ev_status: /* empty */ { $$= 0; }
}
| DISABLE_SYM
{
Lex->event_parse_data->status= Event_parse_data::DISABLED;
LEX *lex=Lex;
if (!lex->et_compile_phase)
@ -1412,10 +1424,12 @@ 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)
{
@ -1443,6 +1457,7 @@ ev_starts: /* empty */
ev_ends: /* empty */
| ENDS_SYM expr
{
Lex->event_parse_data->item_ends= $2;
LEX *lex= Lex;
if (!lex->et_compile_phase)
{
@ -1467,6 +1482,8 @@ opt_ev_on_completion: /* empty */ { $$= 0; }
ev_on_completion:
ON COMPLETION_SYM PRESERVE_SYM
{
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;
@ -1474,6 +1491,8 @@ ev_on_completion:
}
| 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;
@ -1484,6 +1503,7 @@ ev_on_completion:
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)
{
@ -1499,25 +1519,43 @@ ev_sql_stmt:
LEX *lex= Lex;
sp_head *sp;
$<sphead>$= lex->sphead;
if (!lex->sphead)
/*
This stops the following :
- CREATE EVENT ... DO CREATE EVENT ...;
- ALTER EVENT ... DO CREATE EVENT ...;
- CREATE EVENT ... DO ALTER EVENT DO ....;
- CREATE PROCEDURE ... BEGIN CREATE EVENT ... END|
This allows:
- CREATE EVENT ... DO DROP EVENT yyy;
- CREATE EVENT ... DO ALTER EVENT yyy;
(the nested ALTER EVENT can have anything but DO clause)
- ALTER EVENT ... DO ALTER EVENT yyy;
(the nested ALTER EVENT can have anything but DO clause)
- ALTER EVENT ... DO DROP EVENT yyy;
- CREATE PROCEDURE ... BEGIN ALTER EVENT ... END|
(the nested ALTER EVENT can have anything but DO clause)
- CREATE PROCEDURE ... BEGIN DROP EVENT ... END|
*/
if (lex->sphead)
{
if (!(sp= new sp_head()))
YYABORT;
sp->reset_thd_mem_root(YYTHD);
sp->init(lex);
sp->m_type= TYPE_ENUM_PROCEDURE;
lex->sphead= sp;
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
lex->sphead->m_chistics= &lex->sp_chistics;
lex->sphead->m_body_begin= lex->ptr;
my_error(ER_EVENT_RECURSIVITY_FORBIDDEN, MYF(0));
YYABORT;
}
if (!(lex->sphead= new sp_head()))
YYABORT;
lex->sphead->reset_thd_mem_root(YYTHD);
lex->sphead->init(lex);
lex->sphead->m_type= TYPE_ENUM_PROCEDURE;
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
lex->sphead->m_chistics= &lex->sp_chistics;
lex->sphead->m_body_begin= lex->ptr;
Lex->event_parse_data->body_begin= lex->ptr;
if (!lex->et_compile_phase)
lex->et->body_begin= lex->ptr;
@ -1526,18 +1564,16 @@ ev_sql_stmt:
{
LEX *lex=Lex;
if (!$<sphead>1)
{
sp_head *sp= lex->sphead;
// return back to the original memory root ASAP
sp->init_strings(YYTHD, lex, NULL);
sp->restore_thd_mem_root(YYTHD);
// return back to the original memory root ASAP
lex->sphead->init_strings(YYTHD, lex, NULL);
lex->sphead->restore_thd_mem_root(YYTHD);
lex->sp_chistics.suid= SP_IS_SUID;//always the definer!
lex->sp_chistics.suid= SP_IS_SUID;//always the definer!
lex->et->sphead= lex->sphead;
lex->sphead= NULL;
}
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);
@ -4720,16 +4756,11 @@ alter:
LEX *lex=Lex;
Event_timed *et;
if (lex->et)
{
/*
Recursive events 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");
lex->spname= NULL;
if (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
YYABORT;
}
lex->spname= 0;//defensive programming
Lex->event_parse_data->identifier= $3;
if (!(et= new (YYTHD->mem_root) Event_timed()))// implicitly calls Event_timed::init()
YYABORT;
@ -4742,9 +4773,9 @@ alter:
}
/*
We have to turn of CLIENT_MULTI_QUERIES while parsing a
stored procedure, otherwise yylex will chop it into pieces
at each ';'.
We have to turn of CLIENT_MULTI_QUERIES while parsing a
stored procedure, otherwise yylex will chop it into pieces
at each ';'.
*/
$<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
@ -7664,29 +7695,9 @@ drop:
}
| DROP EVENT_SYM if_exists sp_name
{
LEX *lex=Lex;
if (lex->et)
{
/*
Recursive events 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;
}
if (!(lex->et= new (YYTHD->mem_root) Event_timed()))
YYABORT;
if (!lex->et_compile_phase)
{
lex->et->init_name(YYTHD, $4);
lex->et->init_definer(YYTHD);
}
lex->sql_command = SQLCOM_DROP_EVENT;
lex->drop_if_exists= $3;
Lex->drop_if_exists= $3;
Lex->spname= $4;
Lex->sql_command = SQLCOM_DROP_EVENT;
}
| DROP TRIGGER_SYM sp_name
{
@ -8416,12 +8427,8 @@ show_param:
}
| CREATE EVENT_SYM sp_name
{
Lex->sql_command = SQLCOM_SHOW_CREATE_EVENT;
Lex->spname= $3;
Lex->et= new (YYTHD->mem_root) Event_timed();
if (!Lex->et)
YYABORT;
Lex->et->init_definer(YYTHD);
Lex->sql_command = SQLCOM_SHOW_CREATE_EVENT;
}
;
@ -10751,20 +10758,22 @@ subselect_end:
**************************************************************************/
view_or_trigger_or_sp:
definer view_or_trigger_or_sp_tail
view_or_trigger_or_sp_or_event:
definer view_or_trigger_or_sp_or_event_tail
{}
| view_replace_or_algorithm definer view_tail
{}
;
view_or_trigger_or_sp_tail:
view_or_trigger_or_sp_or_event_tail:
view_tail
{}
| trigger_tail
{}
| sp_tail
{}
| event_tail
{}
;
/**************************************************************************