Merge
This commit is contained in:
commit
f92454082a
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
#
|
||||
|
@ -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
|
||||
#
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
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
122
sql/event_db_repository.h
Normal 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
19
sql/event_queue.cc
Normal 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
20
sql/event_queue.h
Normal 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_ */
|
@ -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);
|
||||
|
@ -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;
|
||||
|
||||
|
926
sql/events.cc
926
sql/events.cc
File diff suppressed because it is too large
Load Diff
110
sql/events.h
110
sql/events.h
@ -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 &);
|
||||
|
@ -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_ */
|
@ -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();
|
||||
|
@ -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");
|
||||
|
@ -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"
|
||||
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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()
|
||||
|
@ -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 */
|
||||
|
@ -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
|
||||
|
183
sql/sql_show.cc
183
sql/sql_show.cc
@ -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,
|
||||
|
@ -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 */
|
||||
|
275
sql/sql_yacc.yy
275
sql/sql_yacc.yy
@ -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
|
||||
{}
|
||||
;
|
||||
|
||||
/**************************************************************************
|
||||
|
Loading…
x
Reference in New Issue
Block a user