Merge
This commit is contained in:
commit
f92454082a
@ -1778,3 +1778,8 @@ vio/viotest-sslconnect.cpp
|
|||||||
vio/viotest.cpp
|
vio/viotest.cpp
|
||||||
zlib/*.ds?
|
zlib/*.ds?
|
||||||
zlib/*.vcproj
|
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 \
|
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 \
|
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 \
|
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 \
|
rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \
|
||||||
sql_tablespace.cc \
|
sql_tablespace.cc \
|
||||||
rpl_injector.cc my_user.c partition_info.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
|
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
|
events_test event_starts_test root@localhost RECURRING NULL 20 SECOND # # ENABLED
|
||||||
DROP EVENT event_starts_test;
|
DROP EVENT event_starts_test;
|
||||||
|
create table test_nested(a int);
|
||||||
create event e_43 on schedule every 1 second do set @a = 5;
|
create event e_43 on schedule every 1 second do set @a = 5;
|
||||||
set global event_scheduler = 1;
|
set global event_scheduler = 1;
|
||||||
alter event e_43 do alter event e_43 do set @a = 4;
|
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;
|
select db, name, body, status, interval_field, interval_value from mysql.event;
|
||||||
db name body status interval_field interval_value
|
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 event e_43;
|
||||||
|
drop table test_nested;
|
||||||
"Let's check whether we can use non-qualified names"
|
"Let's check whether we can use non-qualified names"
|
||||||
create table non_qualif(a int);
|
create table non_qualif(a int);
|
||||||
create event non_qualif_ev on schedule every 10 minute do insert into non_qualif values (800219);
|
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;
|
drop event закачка21;
|
||||||
create table t_16 (s1 int);
|
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;
|
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;
|
drop table t_16;
|
||||||
create event white_space
|
create event white_space
|
||||||
on schedule every 10 hour
|
on schedule every 10 hour
|
||||||
|
@ -17,18 +17,7 @@ DROP EVENT ДОЛЕН_регистър_утф8;
|
|||||||
SET NAMES latin1;
|
SET NAMES latin1;
|
||||||
set @a=3;
|
set @a=3;
|
||||||
CREATE PROCEDURE p_16 () CREATE EVENT e_16 ON SCHEDULE EVERY @a SECOND DO SET @a=5;
|
CREATE PROCEDURE p_16 () CREATE EVENT e_16 ON SCHEDULE EVERY @a SECOND DO SET @a=5;
|
||||||
call p_16();
|
ERROR HY000: Recursivity of EVENT DDL statements is forbidden when body is present
|
||||||
"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;
|
|
||||||
create event e_55 on schedule at 99990101000000 do drop table t;
|
create event e_55 on schedule at 99990101000000 do drop table t;
|
||||||
ERROR HY000: Incorrect AT value: '99990101000000'
|
ERROR HY000: Incorrect AT value: '99990101000000'
|
||||||
create event e_55 on schedule every 10 hour starts 99990101000000 do drop table t;
|
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;
|
DROP EVENT event_starts_test;
|
||||||
#
|
#
|
||||||
#
|
#
|
||||||
|
create table test_nested(a int);
|
||||||
create event e_43 on schedule every 1 second do set @a = 5;
|
create event e_43 on schedule every 1 second do set @a = 5;
|
||||||
set global event_scheduler = 1;
|
set global event_scheduler = 1;
|
||||||
--sleep 2
|
--error 1562
|
||||||
alter event e_43 do alter event e_43 do set @a = 4;
|
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;
|
select db, name, body, status, interval_field, interval_value from mysql.event;
|
||||||
drop event e_43;
|
drop event e_43;
|
||||||
--sleep 1
|
drop table test_nested;
|
||||||
|
|
||||||
--echo "Let's check whether we can use non-qualified names"
|
--echo "Let's check whether we can use non-qualified names"
|
||||||
create table non_qualif(a int);
|
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
|
# Bug #16410 Events: CREATE EVENT is legal in a CREATE TRIGGER statement
|
||||||
#
|
#
|
||||||
create table t_16 (s1 int);
|
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;
|
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;
|
drop table t_16;
|
||||||
#
|
#
|
||||||
|
@ -30,19 +30,8 @@ SET NAMES latin1;
|
|||||||
# START - BUG#16408: Events: crash for an event in a procedure
|
# START - BUG#16408: Events: crash for an event in a procedure
|
||||||
#
|
#
|
||||||
set @a=3;
|
set @a=3;
|
||||||
|
--error 1562
|
||||||
CREATE PROCEDURE p_16 () CREATE EVENT e_16 ON SCHEDULE EVERY @a SECOND DO SET @a=5;
|
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
|
# 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_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
|
sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc
|
||||||
time.cc tztime.cc uniques.cc unireg.cc item_xmlfunc.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
|
sql_tablespace.cc events.cc ../sql-common/my_user.c
|
||||||
partition_info.cc rpl_injector.cc
|
partition_info.cc rpl_injector.cc
|
||||||
${PROJECT_SOURCE_DIR}/sql/sql_yacc.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\
|
tztime.h my_decimal.h\
|
||||||
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
|
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
|
||||||
parse_file.h sql_view.h sql_trigger.h \
|
parse_file.h sql_view.h sql_trigger.h \
|
||||||
sql_array.h sql_cursor.h events.h events_priv.h \
|
sql_array.h sql_cursor.h events.h \
|
||||||
sql_plugin.h authors.h sql_partition.h event_timed.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 \
|
partition_info.h partition_element.h event_scheduler.h \
|
||||||
contributors.h
|
contributors.h
|
||||||
mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
|
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\
|
tztime.cc my_time.c my_user.c my_decimal.cc\
|
||||||
sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
|
sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
|
||||||
sp_cache.cc parse_file.cc sql_trigger.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_plugin.cc sql_binlog.cc \
|
||||||
sql_builtin.cc sql_tablespace.cc partition_info.cc
|
sql_builtin.cc sql_tablespace.cc partition_info.cc
|
||||||
|
|
||||||
|
@ -16,12 +16,104 @@
|
|||||||
|
|
||||||
#define MYSQL_LEX 1
|
#define MYSQL_LEX 1
|
||||||
#include "mysql_priv.h"
|
#include "mysql_priv.h"
|
||||||
#include "events_priv.h"
|
|
||||||
#include "events.h"
|
#include "events.h"
|
||||||
#include "event_timed.h"
|
#include "event_data_objects.h"
|
||||||
|
#include "event_db_repository.h"
|
||||||
#include "sp_head.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
|
Constructor
|
||||||
|
|
||||||
@ -644,29 +736,29 @@ Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table)
|
|||||||
|
|
||||||
et= this;
|
et= this;
|
||||||
|
|
||||||
if (table->s->fields != Events::FIELD_COUNT)
|
if (table->s->fields != ET_FIELD_COUNT)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if ((et->dbname.str= get_field(mem_root,
|
if ((et->dbname.str= get_field(mem_root,
|
||||||
table->field[Events::FIELD_DB])) == NULL)
|
table->field[ET_FIELD_DB])) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
et->dbname.length= strlen(et->dbname.str);
|
et->dbname.length= strlen(et->dbname.str);
|
||||||
|
|
||||||
if ((et->name.str= get_field(mem_root,
|
if ((et->name.str= get_field(mem_root,
|
||||||
table->field[Events::FIELD_NAME])) == NULL)
|
table->field[ET_FIELD_NAME])) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
et->name.length= strlen(et->name.str);
|
et->name.length= strlen(et->name.str);
|
||||||
|
|
||||||
if ((et->body.str= get_field(mem_root,
|
if ((et->body.str= get_field(mem_root,
|
||||||
table->field[Events::FIELD_BODY])) == NULL)
|
table->field[ET_FIELD_BODY])) == NULL)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
et->body.length= strlen(et->body.str);
|
et->body.length= strlen(et->body.str);
|
||||||
|
|
||||||
if ((et->definer.str= get_field(mem_root,
|
if ((et->definer.str= get_field(mem_root,
|
||||||
table->field[Events::FIELD_DEFINER])) == NullS)
|
table->field[ET_FIELD_DEFINER])) == NullS)
|
||||||
goto error;
|
goto error;
|
||||||
et->definer.length= strlen(et->definer.str);
|
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.str= strmake_root(mem_root, ptr + 1, len);/* 1:because of @*/
|
||||||
et->definer_host.length= len;
|
et->definer_host.length= len;
|
||||||
|
|
||||||
et->starts_null= table->field[Events::FIELD_STARTS]->is_null();
|
et->starts_null= table->field[ET_FIELD_STARTS]->is_null();
|
||||||
res1= table->field[Events::FIELD_STARTS]->
|
res1= table->field[ET_FIELD_STARTS]->
|
||||||
get_date(&et->starts,TIME_NO_ZERO_DATE);
|
get_date(&et->starts,TIME_NO_ZERO_DATE);
|
||||||
|
|
||||||
et->ends_null= table->field[Events::FIELD_ENDS]->is_null();
|
et->ends_null= table->field[ET_FIELD_ENDS]->is_null();
|
||||||
res2= table->field[Events::FIELD_ENDS]->get_date(&et->ends, TIME_NO_ZERO_DATE);
|
res2= table->field[ET_FIELD_ENDS]->get_date(&et->ends, TIME_NO_ZERO_DATE);
|
||||||
|
|
||||||
if (!table->field[Events::FIELD_INTERVAL_EXPR]->is_null())
|
if (!table->field[ET_FIELD_INTERVAL_EXPR]->is_null())
|
||||||
et->expression= table->field[Events::FIELD_INTERVAL_EXPR]->val_int();
|
et->expression= table->field[ET_FIELD_INTERVAL_EXPR]->val_int();
|
||||||
else
|
else
|
||||||
et->expression= 0;
|
et->expression= 0;
|
||||||
/*
|
/*
|
||||||
If res1 and res2 are true then both fields are empty.
|
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=
|
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 &&
|
DBUG_ASSERT(!(et->starts_null && et->ends_null && !et->expression &&
|
||||||
et->execute_at_null));
|
et->execute_at_null));
|
||||||
if (!et->expression &&
|
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))
|
TIME_NO_ZERO_DATE))
|
||||||
goto error;
|
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
|
In DB the values start from 1 but enum interval_type starts
|
||||||
from 0
|
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)
|
et->interval= (interval_type) ((ulonglong)
|
||||||
table->field[Events::FIELD_TRANSIENT_INTERVAL]->val_int() - 1);
|
table->field[ET_FIELD_TRANSIENT_INTERVAL]->val_int() - 1);
|
||||||
else
|
else
|
||||||
et->interval= (interval_type) 0;
|
et->interval= (interval_type) 0;
|
||||||
|
|
||||||
et->created= table->field[Events::FIELD_CREATED]->val_int();
|
et->created= table->field[ET_FIELD_CREATED]->val_int();
|
||||||
et->modified= table->field[Events::FIELD_MODIFIED]->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);
|
get_date(&et->last_executed, TIME_NO_ZERO_DATE);
|
||||||
|
|
||||||
last_executed_changed= false;
|
last_executed_changed= false;
|
||||||
|
|
||||||
/* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
|
/* 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;
|
goto error;
|
||||||
|
|
||||||
DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", et->name.str, ptr));
|
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 */
|
/* ToDo : Andrey . Find a way not to allocate ptr on event_mem_root */
|
||||||
if ((ptr= get_field(mem_root,
|
if ((ptr= get_field(mem_root,
|
||||||
table->field[Events::FIELD_ON_COMPLETION])) == NullS)
|
table->field[ET_FIELD_ON_COMPLETION])) == NullS)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
et->on_completion= (ptr[0]=='D'? Event_timed::ON_COMPLETION_DROP:
|
et->on_completion= (ptr[0]=='D'? Event_timed::ON_COMPLETION_DROP:
|
||||||
Event_timed::ON_COMPLETION_PRESERVE);
|
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)
|
if (et->comment.str != NullS)
|
||||||
et->comment.length= strlen(et->comment.str);
|
et->comment.length= strlen(et->comment.str);
|
||||||
else
|
else
|
||||||
et->comment.length= 0;
|
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);
|
DBUG_RETURN(0);
|
||||||
error:
|
error:
|
||||||
@ -1188,6 +1280,7 @@ Event_timed::mark_last_executed(THD *thd)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Drops the event
|
Drops the event
|
||||||
|
|
||||||
@ -1210,7 +1303,8 @@ Event_timed::drop(THD *thd)
|
|||||||
uint tmp= 0;
|
uint tmp= 0;
|
||||||
DBUG_ENTER("Event_timed::drop");
|
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);
|
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;
|
ret= EVEX_OPEN_TABLE_FAILED;
|
||||||
goto done;
|
goto done;
|
||||||
@ -1263,15 +1357,15 @@ Event_timed::update_fields(THD *thd)
|
|||||||
|
|
||||||
if (last_executed_changed)
|
if (last_executed_changed)
|
||||||
{
|
{
|
||||||
table->field[Events::FIELD_LAST_EXECUTED]->set_notnull();
|
table->field[ET_FIELD_LAST_EXECUTED]->set_notnull();
|
||||||
table->field[Events::FIELD_LAST_EXECUTED]->store_time(&last_executed,
|
table->field[ET_FIELD_LAST_EXECUTED]->store_time(&last_executed,
|
||||||
MYSQL_TIMESTAMP_DATETIME);
|
MYSQL_TIMESTAMP_DATETIME);
|
||||||
last_executed_changed= false;
|
last_executed_changed= false;
|
||||||
}
|
}
|
||||||
if (status_changed)
|
if (status_changed)
|
||||||
{
|
{
|
||||||
table->field[Events::FIELD_STATUS]->set_notnull();
|
table->field[ET_FIELD_STATUS]->set_notnull();
|
||||||
table->field[Events::FIELD_STATUS]->store((longlong)status, true);
|
table->field[ET_FIELD_STATUS]->store((longlong)status, true);
|
||||||
status_changed= false;
|
status_changed= false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1541,7 +1635,7 @@ Event_timed::compile(THD *thd, MEM_ROOT *mem_root)
|
|||||||
thd->query_length= show_create.length();
|
thd->query_length= show_create.length();
|
||||||
DBUG_PRINT("info", ("query:%s",thd->query));
|
DBUG_PRINT("info", ("query:%s",thd->query));
|
||||||
|
|
||||||
change_security_context(thd, definer_user, definer_host, dbname,
|
thd->change_security_context(definer_user, definer_host, dbname,
|
||||||
&security_ctx, &save_ctx);
|
&security_ctx, &save_ctx);
|
||||||
thd->lex= &lex;
|
thd->lex= &lex;
|
||||||
lex_start(thd, (uchar*)thd->query, thd->query_length);
|
lex_start(thd, (uchar*)thd->query, thd->query_length);
|
||||||
@ -1580,7 +1674,7 @@ done:
|
|||||||
lex.et->deinit_mutexes();
|
lex.et->deinit_mutexes();
|
||||||
|
|
||||||
lex_end(&lex);
|
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"));
|
DBUG_PRINT("note", ("return old data on its place. set back NAMES"));
|
||||||
|
|
||||||
thd->lex= old_lex;
|
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
|
Checks whether two events are equal by identifiers
|
||||||
@ -1814,8 +1891,62 @@ bool
|
|||||||
event_timed_identifier_equal(Event_timed *a, Event_timed *b)
|
event_timed_identifier_equal(Event_timed *a, Event_timed *b)
|
||||||
{
|
{
|
||||||
return event_timed_name_equal(a, &b->name) &&
|
return event_timed_name_equal(a, &b->name) &&
|
||||||
event_timed_db_equal(a, &b->dbname) &&
|
event_timed_db_equal(a, &b->dbname);
|
||||||
event_timed_definer_equal(a, &b->definer);
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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_
|
#ifndef _EVENT_DATA_OBJECTS_H_
|
||||||
#define _EVENT_TIMED_H_
|
#define _EVENT_DATA_OBJECTS_H_
|
||||||
/* Copyright (C) 2004-2006 MySQL AB
|
/* Copyright (C) 2004-2006 MySQL AB
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify
|
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_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 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
|
class Event_timed
|
||||||
{
|
{
|
||||||
@ -214,4 +241,91 @@ public:
|
|||||||
set_thread_id(ulong tid) { thread_id= tid; }
|
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 */
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||||
|
|
||||||
#include "mysql_priv.h"
|
#include "mysql_priv.h"
|
||||||
#include "events_priv.h"
|
|
||||||
#include "events.h"
|
#include "events.h"
|
||||||
#include "event_timed.h"
|
#include "event_data_objects.h"
|
||||||
#include "event_scheduler.h"
|
#include "event_scheduler.h"
|
||||||
|
#include "event_db_repository.h"
|
||||||
#include "sp_head.h"
|
#include "sp_head.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -574,7 +574,7 @@ event_worker_thread(void *arg)
|
|||||||
to change the context before sending the signal. We are under
|
to change the context before sending the signal. We are under
|
||||||
LOCK_scheduler_data being held by Event_scheduler::run() -> ::execute_top().
|
LOCK_scheduler_data being held by Event_scheduler::run() -> ::execute_top().
|
||||||
*/
|
*/
|
||||||
change_security_context(thd, event->definer_user, event->definer_host,
|
thd->change_security_context(event->definer_user, event->definer_host,
|
||||||
event->dbname, &security_ctx, &save_ctx);
|
event->dbname, &security_ctx, &save_ctx);
|
||||||
DBUG_PRINT("info", ("master_access=%d db_access=%d",
|
DBUG_PRINT("info", ("master_access=%d db_access=%d",
|
||||||
thd->security_ctx->master_access, thd->security_ctx->db_access));
|
thd->security_ctx->master_access, thd->security_ctx->db_access));
|
||||||
@ -687,7 +687,7 @@ Event_scheduler::get_instance()
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Event_scheduler::init()
|
Event_scheduler::init(Event_db_repository *db_repo)
|
||||||
{
|
{
|
||||||
int i= 0;
|
int i= 0;
|
||||||
bool ret= FALSE;
|
bool ret= FALSE;
|
||||||
@ -695,6 +695,7 @@ Event_scheduler::init()
|
|||||||
DBUG_PRINT("enter", ("this=%p", this));
|
DBUG_PRINT("enter", ("this=%p", this));
|
||||||
|
|
||||||
LOCK_SCHEDULER_DATA();
|
LOCK_SCHEDULER_DATA();
|
||||||
|
db_repository= db_repo;
|
||||||
for (;i < COND_LAST; i++)
|
for (;i < COND_LAST; i++)
|
||||||
if (pthread_cond_init(&cond_vars[i], NULL))
|
if (pthread_cond_init(&cond_vars[i], NULL))
|
||||||
{
|
{
|
||||||
@ -783,10 +784,10 @@ Event_scheduler::destroy()
|
|||||||
OP_LOAD_ERROR Error during loading from disk
|
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)
|
Event_scheduler::create_event(THD *thd, Event_timed *et, bool check_existence)
|
||||||
{
|
{
|
||||||
enum enum_error_code res;
|
int res;
|
||||||
Event_timed *et_new;
|
Event_timed *et_new;
|
||||||
DBUG_ENTER("Event_scheduler::create_event");
|
DBUG_ENTER("Event_scheduler::create_event");
|
||||||
DBUG_PRINT("enter", ("thd=%p et=%p lock=%p",thd,et,&LOCK_scheduler_data));
|
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 */
|
/* 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);
|
queue_insert_safe(&queue, (byte *) et_new);
|
||||||
DBUG_PRINT("info", ("Sending COND_new_work"));
|
DBUG_PRINT("info", ("Sending COND_new_work"));
|
||||||
@ -833,12 +834,13 @@ end:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
Event_scheduler::drop_event(THD *thd, Event_timed *et)
|
Event_scheduler::drop_event(THD *thd, sp_name *name)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
Event_timed *et_old;
|
Event_timed *et_old;
|
||||||
DBUG_ENTER("Event_scheduler::drop_event");
|
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();
|
LOCK_SCHEDULER_DATA();
|
||||||
if (!is_running_or_suspended())
|
if (!is_running_or_suspended())
|
||||||
@ -848,7 +850,7 @@ Event_scheduler::drop_event(THD *thd, Event_timed *et)
|
|||||||
DBUG_RETURN(OP_OK);
|
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"));
|
DBUG_PRINT("info", ("No such event found, probably DISABLED"));
|
||||||
|
|
||||||
UNLOCK_SCHEDULER_DATA();
|
UNLOCK_SCHEDULER_DATA();
|
||||||
@ -903,12 +905,12 @@ Event_scheduler::drop_event(THD *thd, Event_timed *et)
|
|||||||
OP_ALREADY_EXISTS Event already in the queue
|
OP_ALREADY_EXISTS Event already in the queue
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum Event_scheduler::enum_error_code
|
int
|
||||||
Event_scheduler::update_event(THD *thd, Event_timed *et,
|
Event_scheduler::update_event(THD *thd, Event_timed *et,
|
||||||
LEX_STRING *new_schema,
|
LEX_STRING *new_schema,
|
||||||
LEX_STRING *new_name)
|
LEX_STRING *new_name)
|
||||||
{
|
{
|
||||||
enum enum_error_code res;
|
int res= OP_OK;
|
||||||
Event_timed *et_old, *et_new= NULL;
|
Event_timed *et_old, *et_new= NULL;
|
||||||
LEX_STRING old_schema, old_name;
|
LEX_STRING old_schema, old_name;
|
||||||
|
|
||||||
@ -946,7 +948,7 @@ Event_scheduler::update_event(THD *thd, Event_timed *et,
|
|||||||
1. Error occured
|
1. Error occured
|
||||||
2. If the replace is DISABLED, we don't load it into the queue.
|
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);
|
queue_insert_safe(&queue, (byte *) et_new);
|
||||||
DBUG_PRINT("info", ("Sending COND_new_work"));
|
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->dbname= old_schema;
|
||||||
et->name= old_name;
|
et->name= old_name;
|
||||||
}
|
}
|
||||||
|
DBUG_PRINT("info", ("res=%d", res));
|
||||||
UNLOCK_SCHEDULER_DATA();
|
UNLOCK_SCHEDULER_DATA();
|
||||||
/*
|
/*
|
||||||
Andrey: Is this comment still truthful ???
|
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
|
Drops all events from the in-memory queue and disk that match
|
||||||
certain pattern evaluated by a comparator function
|
certain pattern evaluated by a comparator function
|
||||||
@ -1068,11 +1112,11 @@ Event_scheduler::find_event(Event_timed *etn, bool remove_from_q)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
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 *))
|
bool (*comparator)(Event_timed *,LEX_STRING *))
|
||||||
{
|
{
|
||||||
DBUG_ENTER("Event_scheduler::drop_matching_events");
|
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));
|
state));
|
||||||
if (is_running_or_suspended())
|
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);
|
Event_timed *et= (Event_timed *) queue_element(&queue, i);
|
||||||
DBUG_PRINT("info", ("[%s.%s]?", et->dbname.str, et->name.str));
|
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
|
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
|
int
|
||||||
Event_scheduler::drop_schema_events(THD *thd, LEX_STRING *schema)
|
Event_scheduler::drop_schema_events(THD *thd, LEX_STRING schema)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
DBUG_ENTER("Event_scheduler::drop_schema_events");
|
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())
|
if (is_running_or_suspended())
|
||||||
drop_matching_events(thd, schema, event_timed_db_equal);
|
drop_matching_events(thd, schema, event_timed_db_equal);
|
||||||
|
|
||||||
ret= db_drop_events_from_table(thd, schema);
|
|
||||||
UNLOCK_SCHEDULER_DATA();
|
UNLOCK_SCHEDULER_DATA();
|
||||||
|
|
||||||
DBUG_RETURN(ret);
|
DBUG_RETURN(ret);
|
||||||
@ -1670,7 +1713,7 @@ Event_scheduler::stop_all_running_events(THD *thd)
|
|||||||
The caller must have acquited LOCK_scheduler_data.
|
The caller must have acquited LOCK_scheduler_data.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum Event_scheduler::enum_error_code
|
int
|
||||||
Event_scheduler::stop()
|
Event_scheduler::stop()
|
||||||
{
|
{
|
||||||
THD *thd= current_thd;
|
THD *thd= current_thd;
|
||||||
@ -1735,7 +1778,7 @@ Event_scheduler::stop()
|
|||||||
OP_OK OK
|
OP_OK OK
|
||||||
*/
|
*/
|
||||||
|
|
||||||
enum Event_scheduler::enum_error_code
|
int
|
||||||
Event_scheduler::suspend_or_resume(
|
Event_scheduler::suspend_or_resume(
|
||||||
enum Event_scheduler::enum_suspend_or_resume action)
|
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);
|
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.");
|
sql_print_error("SCHEDULER: Table mysql.event is damaged. Can not open.");
|
||||||
DBUG_RETURN(EVEX_OPEN_TABLE_FAILED);
|
DBUG_RETURN(EVEX_OPEN_TABLE_FAILED);
|
||||||
|
@ -16,7 +16,9 @@
|
|||||||
along with this program; if not, write to the Free Software
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||||
|
|
||||||
|
class sp_name;
|
||||||
class Event_timed;
|
class Event_timed;
|
||||||
|
class Event_db_repository;
|
||||||
|
|
||||||
class THD;
|
class THD;
|
||||||
typedef bool * (*event_timed_identifier_comparator)(Event_timed*, Event_timed*);
|
typedef bool * (*event_timed_identifier_comparator)(Event_timed*, Event_timed*);
|
||||||
@ -30,17 +32,6 @@ events_shutdown();
|
|||||||
class Event_scheduler
|
class Event_scheduler
|
||||||
{
|
{
|
||||||
public:
|
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
|
enum enum_state
|
||||||
{
|
{
|
||||||
@ -65,22 +56,22 @@ public:
|
|||||||
|
|
||||||
/* Methods for queue management follow */
|
/* Methods for queue management follow */
|
||||||
|
|
||||||
enum enum_error_code
|
int
|
||||||
create_event(THD *thd, Event_timed *et, bool check_existence);
|
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,
|
update_event(THD *thd, Event_timed *et, LEX_STRING *new_schema,
|
||||||
LEX_STRING *new_name);
|
LEX_STRING *new_name);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
drop_event(THD *thd, Event_timed *et);
|
drop_event(THD *thd, sp_name *name);
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
drop_schema_events(THD *thd, LEX_STRING *schema);
|
drop_schema_events(THD *thd, LEX_STRING schema);
|
||||||
|
|
||||||
int
|
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;}
|
{ DBUG_ASSERT(0); return 0;}
|
||||||
|
|
||||||
uint
|
uint
|
||||||
@ -91,20 +82,24 @@ public:
|
|||||||
bool
|
bool
|
||||||
start();
|
start();
|
||||||
|
|
||||||
enum enum_error_code
|
int
|
||||||
stop();
|
stop();
|
||||||
|
|
||||||
bool
|
bool
|
||||||
start_suspended();
|
start_suspended();
|
||||||
|
|
||||||
|
/*
|
||||||
|
Need to be public because has to be called from the function
|
||||||
|
passed to pthread_create.
|
||||||
|
*/
|
||||||
bool
|
bool
|
||||||
run(THD *thd);
|
run(THD *thd);
|
||||||
|
|
||||||
enum enum_error_code
|
int
|
||||||
suspend_or_resume(enum enum_suspend_or_resume action);
|
suspend_or_resume(enum enum_suspend_or_resume action);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
init();
|
init(Event_db_repository *db_repo);
|
||||||
|
|
||||||
void
|
void
|
||||||
destroy();
|
destroy();
|
||||||
@ -136,6 +131,9 @@ private:
|
|||||||
Event_timed *
|
Event_timed *
|
||||||
find_event(Event_timed *etn, bool remove_from_q);
|
find_event(Event_timed *etn, bool remove_from_q);
|
||||||
|
|
||||||
|
Event_timed *
|
||||||
|
find_event(sp_name *name, bool remove_from_q);
|
||||||
|
|
||||||
uint
|
uint
|
||||||
workers_count();
|
workers_count();
|
||||||
|
|
||||||
@ -152,14 +150,11 @@ private:
|
|||||||
void
|
void
|
||||||
stop_all_running_events(THD *thd);
|
stop_all_running_events(THD *thd);
|
||||||
|
|
||||||
enum enum_error_code
|
|
||||||
load_named_event(THD *thd, Event_timed *etn, Event_timed **etn_new);
|
|
||||||
|
|
||||||
int
|
int
|
||||||
load_events_from_db(THD *thd);
|
load_events_from_db(THD *thd);
|
||||||
|
|
||||||
void
|
void
|
||||||
drop_matching_events(THD *thd, LEX_STRING *pattern,
|
drop_matching_events(THD *thd, LEX_STRING pattern,
|
||||||
bool (*)(Event_timed *,LEX_STRING *));
|
bool (*)(Event_timed *,LEX_STRING *));
|
||||||
|
|
||||||
bool
|
bool
|
||||||
@ -226,6 +221,8 @@ private:
|
|||||||
/* The MEM_ROOT of the object */
|
/* The MEM_ROOT of the object */
|
||||||
MEM_ROOT scheduler_root;
|
MEM_ROOT scheduler_root;
|
||||||
|
|
||||||
|
Event_db_repository *db_repository;
|
||||||
|
|
||||||
/* The sorted queue with the Event_timed objects */
|
/* The sorted queue with the Event_timed objects */
|
||||||
QUEUE queue;
|
QUEUE queue;
|
||||||
|
|
||||||
|
916
sql/events.cc
916
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
|
along with this program; if not, write to the Free Software
|
||||||
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
|
||||||
|
|
||||||
|
class sp_name;
|
||||||
class Event_timed;
|
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
|
class Events
|
||||||
{
|
{
|
||||||
public:
|
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 ulong opt_event_scheduler;
|
||||||
static TYPELIB opt_typelib;
|
static TYPELIB opt_typelib;
|
||||||
|
|
||||||
enum enum_table_field
|
int
|
||||||
{
|
init();
|
||||||
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 :) */
|
|
||||||
};
|
|
||||||
|
|
||||||
static int
|
void
|
||||||
create_event(THD *thd, Event_timed *et, uint create_options,
|
deinit();
|
||||||
uint *rows_affected);
|
|
||||||
|
|
||||||
static int
|
void
|
||||||
update_event(THD *thd, Event_timed *et, sp_name *new_name,
|
init_mutexes();
|
||||||
uint *rows_affected);
|
|
||||||
|
|
||||||
static int
|
void
|
||||||
drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
|
destroy_mutexes();
|
||||||
uint *rows_affected);
|
|
||||||
|
|
||||||
static int
|
static Events*
|
||||||
|
get_instance();
|
||||||
|
|
||||||
|
int
|
||||||
|
create_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
|
||||||
|
uint create_options, uint *rows_affected);
|
||||||
|
|
||||||
|
int
|
||||||
|
update_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
|
||||||
|
sp_name *new_name, uint *rows_affected);
|
||||||
|
|
||||||
|
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);
|
open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
|
||||||
|
|
||||||
static int
|
int
|
||||||
show_create_event(THD *thd, sp_name *spn);
|
show_create_event(THD *thd, sp_name *spn);
|
||||||
|
|
||||||
|
/* Needed for both SHOW CREATE EVENT and INFORMATION_SCHEMA */
|
||||||
static int
|
static int
|
||||||
reconstruct_interval_expression(String *buf, interval_type interval,
|
reconstruct_interval_expression(String *buf, interval_type interval,
|
||||||
longlong expression);
|
longlong expression);
|
||||||
|
|
||||||
static int
|
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);
|
dump_internal_status(THD *thd);
|
||||||
|
|
||||||
static int
|
Event_db_repository *db_repository;
|
||||||
init();
|
|
||||||
|
|
||||||
static void
|
|
||||||
shutdown();
|
|
||||||
|
|
||||||
static void
|
|
||||||
init_mutexes();
|
|
||||||
|
|
||||||
static void
|
|
||||||
destroy_mutexes();
|
|
||||||
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/* Singleton DP is used */
|
||||||
|
Events(){}
|
||||||
|
~Events(){}
|
||||||
|
|
||||||
|
/* Singleton instance */
|
||||||
|
static Events singleton;
|
||||||
|
|
||||||
/* Prevent use of these */
|
/* Prevent use of these */
|
||||||
Events(const Events &);
|
Events(const Events &);
|
||||||
void operator=(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
|
(void) pthread_mutex_unlock(&LOCK_thread_count); // For unlink from list
|
||||||
|
|
||||||
Events::shutdown();
|
Events::get_instance()->deinit();
|
||||||
end_slave();
|
end_slave();
|
||||||
|
|
||||||
if (thread_count)
|
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_sent);
|
||||||
(void) pthread_mutex_destroy(&LOCK_bytes_received);
|
(void) pthread_mutex_destroy(&LOCK_bytes_received);
|
||||||
(void) pthread_mutex_destroy(&LOCK_user_conn);
|
(void) pthread_mutex_destroy(&LOCK_user_conn);
|
||||||
Events::destroy_mutexes();
|
Events::get_instance()->destroy_mutexes();
|
||||||
#ifdef HAVE_OPENSSL
|
#ifdef HAVE_OPENSSL
|
||||||
(void) pthread_mutex_destroy(&LOCK_des_key_file);
|
(void) pthread_mutex_destroy(&LOCK_des_key_file);
|
||||||
#ifndef HAVE_YASSL
|
#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_mutex_init(&LOCK_server_started, MY_MUTEX_INIT_FAST);
|
||||||
(void) pthread_cond_init(&COND_server_started,NULL);
|
(void) pthread_cond_init(&COND_server_started,NULL);
|
||||||
sp_cache_init();
|
sp_cache_init();
|
||||||
Events::init_mutexes();
|
Events::get_instance()->init_mutexes();
|
||||||
/* Parameter for threads created for connections */
|
/* Parameter for threads created for connections */
|
||||||
(void) pthread_attr_init(&connection_attrib);
|
(void) pthread_attr_init(&connection_attrib);
|
||||||
(void) pthread_attr_setdetachstate(&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)
|
if (!opt_noacl)
|
||||||
{
|
{
|
||||||
Events::init();
|
Events::get_instance()->init();
|
||||||
}
|
}
|
||||||
#if defined(__NT__) || defined(HAVE_SMEM)
|
#if defined(__NT__) || defined(HAVE_SMEM)
|
||||||
handle_connections_methods();
|
handle_connections_methods();
|
||||||
|
@ -3892,7 +3892,7 @@ byte *sys_var_thd_dbug::value_ptr(THD *thd, enum_var_type type, LEX_STRING *b)
|
|||||||
bool
|
bool
|
||||||
sys_var_event_scheduler::update(THD *thd, set_var *var)
|
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();
|
Event_scheduler *scheduler= Event_scheduler::get_instance();
|
||||||
/* here start the thread if not running. */
|
/* here start the thread if not running. */
|
||||||
DBUG_ENTER("sys_var_event_scheduler::update");
|
DBUG_ENTER("sys_var_event_scheduler::update");
|
||||||
|
@ -5839,3 +5839,6 @@ ER_CANT_ACTIVATE_LOG
|
|||||||
eng "Cannot activate '%-.64s' log."
|
eng "Cannot activate '%-.64s' log."
|
||||||
ER_RBR_NOT_AVAILABLE
|
ER_RBR_NOT_AVAILABLE
|
||||||
eng "The server was not built with row-based replication"
|
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;
|
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.
|
Handling of open and locked tables states.
|
||||||
|
|
||||||
|
@ -869,6 +869,14 @@ public:
|
|||||||
Security_context main_security_ctx;
|
Security_context main_security_ctx;
|
||||||
Security_context *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 */
|
/* remote (peer) port */
|
||||||
uint16 peer_port;
|
uint16 peer_port;
|
||||||
/*
|
/*
|
||||||
|
@ -904,7 +904,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
|
|||||||
|
|
||||||
exit:
|
exit:
|
||||||
(void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */
|
(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
|
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()
|
client's selected database to nothing (to have an empty SELECT DATABASE()
|
||||||
|
@ -28,6 +28,7 @@ class sp_pcontext;
|
|||||||
class st_alter_tablespace;
|
class st_alter_tablespace;
|
||||||
class partition_info;
|
class partition_info;
|
||||||
class Event_timed;
|
class Event_timed;
|
||||||
|
class Event_parse_data;
|
||||||
|
|
||||||
#ifdef MYSQL_SERVER
|
#ifdef MYSQL_SERVER
|
||||||
/*
|
/*
|
||||||
@ -1017,6 +1018,7 @@ typedef struct st_lex : public Query_tables_list
|
|||||||
st_sp_chistics sp_chistics;
|
st_sp_chistics sp_chistics;
|
||||||
|
|
||||||
Event_timed *et;
|
Event_timed *et;
|
||||||
|
Event_parse_data *event_parse_data;
|
||||||
bool et_compile_phase;
|
bool et_compile_phase;
|
||||||
|
|
||||||
bool only_view; /* used for SHOW CREATE TABLE/VIEW */
|
bool only_view; /* used for SHOW CREATE TABLE/VIEW */
|
||||||
|
@ -27,7 +27,7 @@
|
|||||||
#include "sp.h"
|
#include "sp.h"
|
||||||
#include "sp_cache.h"
|
#include "sp_cache.h"
|
||||||
#include "events.h"
|
#include "events.h"
|
||||||
#include "event_timed.h"
|
#include "event_data_objects.h"
|
||||||
|
|
||||||
#ifdef HAVE_OPENSSL
|
#ifdef HAVE_OPENSSL
|
||||||
/*
|
/*
|
||||||
@ -3831,7 +3831,6 @@ end_with_restore_list:
|
|||||||
}
|
}
|
||||||
case SQLCOM_CREATE_EVENT:
|
case SQLCOM_CREATE_EVENT:
|
||||||
case SQLCOM_ALTER_EVENT:
|
case SQLCOM_ALTER_EVENT:
|
||||||
case SQLCOM_DROP_EVENT:
|
|
||||||
{
|
{
|
||||||
uint rows_affected= 1;
|
uint rows_affected= 1;
|
||||||
DBUG_ASSERT(lex->et);
|
DBUG_ASSERT(lex->et);
|
||||||
@ -3860,17 +3859,15 @@ end_with_restore_list:
|
|||||||
|
|
||||||
switch (lex->sql_command) {
|
switch (lex->sql_command) {
|
||||||
case SQLCOM_CREATE_EVENT:
|
case SQLCOM_CREATE_EVENT:
|
||||||
res= Events::create_event(thd, lex->et,
|
res= Events::get_instance()->
|
||||||
(uint) lex->create_info.options,
|
create_event(thd, lex->et, lex->event_parse_data,
|
||||||
&rows_affected);
|
(uint) lex->create_info.options, &rows_affected);
|
||||||
break;
|
break;
|
||||||
case SQLCOM_ALTER_EVENT:
|
case SQLCOM_ALTER_EVENT:
|
||||||
res= Events::update_event(thd, lex->et, lex->spname,
|
res= Events::get_instance()->
|
||||||
&rows_affected);
|
update_event(thd, lex->et, lex->event_parse_data,
|
||||||
|
lex->spname, &rows_affected);
|
||||||
break;
|
break;
|
||||||
case SQLCOM_DROP_EVENT:
|
|
||||||
res= Events::drop_event(thd, lex->et, lex->drop_if_exists,
|
|
||||||
&rows_affected);
|
|
||||||
default:;
|
default:;
|
||||||
}
|
}
|
||||||
DBUG_PRINT("info", ("CREATE/ALTER/DROP returned error code=%d af_rows=%d",
|
DBUG_PRINT("info", ("CREATE/ALTER/DROP returned error code=%d af_rows=%d",
|
||||||
@ -3889,10 +3886,10 @@ end_with_restore_list:
|
|||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case SQLCOM_DROP_EVENT:
|
||||||
case SQLCOM_SHOW_CREATE_EVENT:
|
case SQLCOM_SHOW_CREATE_EVENT:
|
||||||
{
|
{
|
||||||
DBUG_ASSERT(lex->spname);
|
DBUG_ASSERT(lex->spname);
|
||||||
DBUG_ASSERT(lex->et);
|
|
||||||
if (! lex->spname->m_db.str)
|
if (! lex->spname->m_db.str)
|
||||||
{
|
{
|
||||||
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
|
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)
|
if (lex->spname->m_name.length > NAME_LEN)
|
||||||
{
|
{
|
||||||
my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
|
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;
|
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;
|
break;
|
||||||
}
|
}
|
||||||
#ifndef DBUG_OFF
|
#ifndef DBUG_OFF
|
||||||
case SQLCOM_SHOW_SCHEDULER_STATUS:
|
case SQLCOM_SHOW_SCHEDULER_STATUS:
|
||||||
{
|
{
|
||||||
res= Events::dump_internal_status(thd);
|
res= Events::get_instance()->dump_internal_status(thd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
183
sql/sql_show.cc
183
sql/sql_show.cc
@ -27,7 +27,7 @@
|
|||||||
#include "authors.h"
|
#include "authors.h"
|
||||||
#include "contributors.h"
|
#include "contributors.h"
|
||||||
#include "events.h"
|
#include "events.h"
|
||||||
#include "event_timed.h"
|
#include "event_data_objects.h"
|
||||||
#include <my_dir.h>
|
#include <my_dir.h>
|
||||||
|
|
||||||
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
#ifdef WITH_PARTITION_STORAGE_ENGINE
|
||||||
@ -4166,7 +4166,7 @@ extern LEX_STRING interval_type_to_name[];
|
|||||||
1 Error
|
1 Error
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static int
|
int
|
||||||
copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
|
copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
|
||||||
{
|
{
|
||||||
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
|
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)
|
int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond)
|
||||||
{
|
{
|
||||||
DBUG_ENTER("fill_open_tables");
|
DBUG_ENTER("fill_open_tables");
|
||||||
@ -5574,7 +5397,7 @@ ST_SCHEMA_TABLE schema_tables[]=
|
|||||||
{"ENGINES", engines_fields_info, create_schema_table,
|
{"ENGINES", engines_fields_info, create_schema_table,
|
||||||
fill_schema_engines, make_old_format, 0, -1, -1, 0},
|
fill_schema_engines, make_old_format, 0, -1, -1, 0},
|
||||||
{"EVENTS", events_fields_info, create_schema_table,
|
{"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,
|
{"FILES", files_fields_info, create_schema_table,
|
||||||
fill_schema_files, 0, 0, -1, -1, 0},
|
fill_schema_files, 0, 0, -1, -1, 0},
|
||||||
{"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table,
|
{"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);
|
HA_CREATE_INFO *create_info_arg);
|
||||||
int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff);
|
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 */
|
#endif /* SQL_SHOW_H */
|
||||||
|
247
sql/sql_yacc.yy
247
sql/sql_yacc.yy
@ -38,7 +38,7 @@
|
|||||||
#include "sp_pcontext.h"
|
#include "sp_pcontext.h"
|
||||||
#include "sp_rcontext.h"
|
#include "sp_rcontext.h"
|
||||||
#include "sp.h"
|
#include "sp.h"
|
||||||
#include "event_timed.h"
|
#include "event_data_objects.h"
|
||||||
#include <myisam.h>
|
#include <myisam.h>
|
||||||
#include <myisammrg.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
|
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
|
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
|
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_suid view_tail view_list_opt view_list view_select
|
||||||
view_check_option trigger_tail sp_tail
|
view_check_option trigger_tail sp_tail
|
||||||
install uninstall partition_entry binlog_base64_event
|
install uninstall partition_entry binlog_base64_event
|
||||||
@ -1257,73 +1258,13 @@ create:
|
|||||||
lex->name=$4.str;
|
lex->name=$4.str;
|
||||||
lex->create_info.options=$3;
|
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
|
| CREATE
|
||||||
{
|
{
|
||||||
Lex->create_view_mode= VIEW_CREATE_NEW;
|
Lex->create_view_mode= VIEW_CREATE_NEW;
|
||||||
Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED;
|
Lex->create_view_algorithm= VIEW_ALGORITHM_UNDEFINED;
|
||||||
Lex->create_view_suid= TRUE;
|
Lex->create_view_suid= TRUE;
|
||||||
}
|
}
|
||||||
view_or_trigger_or_sp
|
view_or_trigger_or_sp_or_event
|
||||||
{}
|
{}
|
||||||
| CREATE USER clear_privileges grant_list
|
| 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
|
ev_schedule_time: EVERY_SYM expr interval
|
||||||
{
|
{
|
||||||
|
Lex->event_parse_data->item_expression= $2;
|
||||||
|
Lex->event_parse_data->interval= $3;
|
||||||
LEX *lex=Lex;
|
LEX *lex=Lex;
|
||||||
if (!lex->et_compile_phase)
|
if (!lex->et_compile_phase)
|
||||||
{
|
{
|
||||||
@ -1365,6 +1374,7 @@ ev_schedule_time: EVERY_SYM expr interval
|
|||||||
ev_ends
|
ev_ends
|
||||||
| AT_SYM expr
|
| AT_SYM expr
|
||||||
{
|
{
|
||||||
|
Lex->event_parse_data->item_execute_at= $2;
|
||||||
LEX *lex=Lex;
|
LEX *lex=Lex;
|
||||||
if (!lex->et_compile_phase)
|
if (!lex->et_compile_phase)
|
||||||
{
|
{
|
||||||
@ -1395,6 +1405,7 @@ ev_schedule_time: EVERY_SYM expr interval
|
|||||||
opt_ev_status: /* empty */ { $$= 0; }
|
opt_ev_status: /* empty */ { $$= 0; }
|
||||||
| ENABLE_SYM
|
| ENABLE_SYM
|
||||||
{
|
{
|
||||||
|
Lex->event_parse_data->status= Event_parse_data::ENABLED;
|
||||||
LEX *lex=Lex;
|
LEX *lex=Lex;
|
||||||
if (!lex->et_compile_phase)
|
if (!lex->et_compile_phase)
|
||||||
lex->et->status= Event_timed::ENABLED;
|
lex->et->status= Event_timed::ENABLED;
|
||||||
@ -1402,6 +1413,7 @@ opt_ev_status: /* empty */ { $$= 0; }
|
|||||||
}
|
}
|
||||||
| DISABLE_SYM
|
| DISABLE_SYM
|
||||||
{
|
{
|
||||||
|
Lex->event_parse_data->status= Event_parse_data::DISABLED;
|
||||||
LEX *lex=Lex;
|
LEX *lex=Lex;
|
||||||
|
|
||||||
if (!lex->et_compile_phase)
|
if (!lex->et_compile_phase)
|
||||||
@ -1412,10 +1424,12 @@ opt_ev_status: /* empty */ { $$= 0; }
|
|||||||
|
|
||||||
ev_starts: /* empty */
|
ev_starts: /* empty */
|
||||||
{
|
{
|
||||||
|
Lex->event_parse_data->item_starts= new Item_func_now_local();
|
||||||
Lex->et->init_starts(YYTHD, new Item_func_now_local());
|
Lex->et->init_starts(YYTHD, new Item_func_now_local());
|
||||||
}
|
}
|
||||||
| STARTS_SYM expr
|
| STARTS_SYM expr
|
||||||
{
|
{
|
||||||
|
Lex->event_parse_data->item_starts= $2;
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
if (!lex->et_compile_phase)
|
if (!lex->et_compile_phase)
|
||||||
{
|
{
|
||||||
@ -1443,6 +1457,7 @@ ev_starts: /* empty */
|
|||||||
ev_ends: /* empty */
|
ev_ends: /* empty */
|
||||||
| ENDS_SYM expr
|
| ENDS_SYM expr
|
||||||
{
|
{
|
||||||
|
Lex->event_parse_data->item_ends= $2;
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
if (!lex->et_compile_phase)
|
if (!lex->et_compile_phase)
|
||||||
{
|
{
|
||||||
@ -1467,6 +1482,8 @@ opt_ev_on_completion: /* empty */ { $$= 0; }
|
|||||||
ev_on_completion:
|
ev_on_completion:
|
||||||
ON COMPLETION_SYM PRESERVE_SYM
|
ON COMPLETION_SYM PRESERVE_SYM
|
||||||
{
|
{
|
||||||
|
Lex->event_parse_data->on_completion=
|
||||||
|
Event_parse_data::ON_COMPLETION_PRESERVE;
|
||||||
LEX *lex=Lex;
|
LEX *lex=Lex;
|
||||||
if (!lex->et_compile_phase)
|
if (!lex->et_compile_phase)
|
||||||
lex->et->on_completion= Event_timed::ON_COMPLETION_PRESERVE;
|
lex->et->on_completion= Event_timed::ON_COMPLETION_PRESERVE;
|
||||||
@ -1474,6 +1491,8 @@ ev_on_completion:
|
|||||||
}
|
}
|
||||||
| ON COMPLETION_SYM NOT_SYM PRESERVE_SYM
|
| ON COMPLETION_SYM NOT_SYM PRESERVE_SYM
|
||||||
{
|
{
|
||||||
|
Lex->event_parse_data->on_completion=
|
||||||
|
Event_parse_data::ON_COMPLETION_DROP;
|
||||||
LEX *lex=Lex;
|
LEX *lex=Lex;
|
||||||
if (!lex->et_compile_phase)
|
if (!lex->et_compile_phase)
|
||||||
lex->et->on_completion= Event_timed::ON_COMPLETION_DROP;
|
lex->et->on_completion= Event_timed::ON_COMPLETION_DROP;
|
||||||
@ -1484,6 +1503,7 @@ ev_on_completion:
|
|||||||
opt_ev_comment: /* empty */ { $$= 0; }
|
opt_ev_comment: /* empty */ { $$= 0; }
|
||||||
| COMMENT_SYM TEXT_STRING_sys
|
| COMMENT_SYM TEXT_STRING_sys
|
||||||
{
|
{
|
||||||
|
Lex->comment= Lex->event_parse_data->comment= $2;
|
||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
if (!lex->et_compile_phase)
|
if (!lex->et_compile_phase)
|
||||||
{
|
{
|
||||||
@ -1499,25 +1519,43 @@ ev_sql_stmt:
|
|||||||
LEX *lex= Lex;
|
LEX *lex= Lex;
|
||||||
sp_head *sp;
|
sp_head *sp;
|
||||||
|
|
||||||
$<sphead>$= lex->sphead;
|
/*
|
||||||
|
This stops the following :
|
||||||
if (!lex->sphead)
|
- 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()))
|
my_error(ER_EVENT_RECURSIVITY_FORBIDDEN, MYF(0));
|
||||||
|
YYABORT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(lex->sphead= new sp_head()))
|
||||||
YYABORT;
|
YYABORT;
|
||||||
|
|
||||||
sp->reset_thd_mem_root(YYTHD);
|
lex->sphead->reset_thd_mem_root(YYTHD);
|
||||||
sp->init(lex);
|
lex->sphead->init(lex);
|
||||||
|
|
||||||
sp->m_type= TYPE_ENUM_PROCEDURE;
|
lex->sphead->m_type= TYPE_ENUM_PROCEDURE;
|
||||||
|
|
||||||
lex->sphead= sp;
|
|
||||||
|
|
||||||
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
|
bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
|
||||||
lex->sphead->m_chistics= &lex->sp_chistics;
|
lex->sphead->m_chistics= &lex->sp_chistics;
|
||||||
|
|
||||||
lex->sphead->m_body_begin= lex->ptr;
|
lex->sphead->m_body_begin= lex->ptr;
|
||||||
}
|
|
||||||
|
Lex->event_parse_data->body_begin= lex->ptr;
|
||||||
|
|
||||||
if (!lex->et_compile_phase)
|
if (!lex->et_compile_phase)
|
||||||
lex->et->body_begin= lex->ptr;
|
lex->et->body_begin= lex->ptr;
|
||||||
@ -1526,18 +1564,16 @@ ev_sql_stmt:
|
|||||||
{
|
{
|
||||||
LEX *lex=Lex;
|
LEX *lex=Lex;
|
||||||
|
|
||||||
if (!$<sphead>1)
|
|
||||||
{
|
|
||||||
sp_head *sp= lex->sphead;
|
|
||||||
// return back to the original memory root ASAP
|
// return back to the original memory root ASAP
|
||||||
sp->init_strings(YYTHD, lex, NULL);
|
lex->sphead->init_strings(YYTHD, lex, NULL);
|
||||||
sp->restore_thd_mem_root(YYTHD);
|
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->et->sphead= lex->sphead;
|
||||||
lex->sphead= NULL;
|
lex->sphead= NULL;
|
||||||
}
|
|
||||||
|
Lex->event_parse_data->init_body(YYTHD);
|
||||||
if (!lex->et_compile_phase)
|
if (!lex->et_compile_phase)
|
||||||
{
|
{
|
||||||
lex->et->init_body(YYTHD);
|
lex->et->init_body(YYTHD);
|
||||||
@ -4720,16 +4756,11 @@ alter:
|
|||||||
LEX *lex=Lex;
|
LEX *lex=Lex;
|
||||||
Event_timed *et;
|
Event_timed *et;
|
||||||
|
|
||||||
if (lex->et)
|
lex->spname= NULL;
|
||||||
{
|
|
||||||
/*
|
if (!(Lex->event_parse_data= Event_parse_data::new_instance(YYTHD)))
|
||||||
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;
|
YYABORT;
|
||||||
}
|
Lex->event_parse_data->identifier= $3;
|
||||||
lex->spname= 0;//defensive programming
|
|
||||||
|
|
||||||
if (!(et= new (YYTHD->mem_root) Event_timed()))// implicitly calls Event_timed::init()
|
if (!(et= new (YYTHD->mem_root) Event_timed()))// implicitly calls Event_timed::init()
|
||||||
YYABORT;
|
YYABORT;
|
||||||
@ -7664,29 +7695,9 @@ drop:
|
|||||||
}
|
}
|
||||||
| DROP EVENT_SYM if_exists sp_name
|
| DROP EVENT_SYM if_exists sp_name
|
||||||
{
|
{
|
||||||
LEX *lex=Lex;
|
Lex->drop_if_exists= $3;
|
||||||
|
Lex->spname= $4;
|
||||||
if (lex->et)
|
Lex->sql_command = SQLCOM_DROP_EVENT;
|
||||||
{
|
|
||||||
/*
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
| DROP TRIGGER_SYM sp_name
|
| DROP TRIGGER_SYM sp_name
|
||||||
{
|
{
|
||||||
@ -8416,12 +8427,8 @@ show_param:
|
|||||||
}
|
}
|
||||||
| CREATE EVENT_SYM sp_name
|
| CREATE EVENT_SYM sp_name
|
||||||
{
|
{
|
||||||
Lex->sql_command = SQLCOM_SHOW_CREATE_EVENT;
|
|
||||||
Lex->spname= $3;
|
Lex->spname= $3;
|
||||||
Lex->et= new (YYTHD->mem_root) Event_timed();
|
Lex->sql_command = SQLCOM_SHOW_CREATE_EVENT;
|
||||||
if (!Lex->et)
|
|
||||||
YYABORT;
|
|
||||||
Lex->et->init_definer(YYTHD);
|
|
||||||
}
|
}
|
||||||
;
|
;
|
||||||
|
|
||||||
@ -10751,20 +10758,22 @@ subselect_end:
|
|||||||
|
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
view_or_trigger_or_sp:
|
view_or_trigger_or_sp_or_event:
|
||||||
definer view_or_trigger_or_sp_tail
|
definer view_or_trigger_or_sp_or_event_tail
|
||||||
{}
|
{}
|
||||||
| view_replace_or_algorithm definer view_tail
|
| view_replace_or_algorithm definer view_tail
|
||||||
{}
|
{}
|
||||||
;
|
;
|
||||||
|
|
||||||
view_or_trigger_or_sp_tail:
|
view_or_trigger_or_sp_or_event_tail:
|
||||||
view_tail
|
view_tail
|
||||||
{}
|
{}
|
||||||
| trigger_tail
|
| trigger_tail
|
||||||
{}
|
{}
|
||||||
| sp_tail
|
| sp_tail
|
||||||
{}
|
{}
|
||||||
|
| event_tail
|
||||||
|
{}
|
||||||
;
|
;
|
||||||
|
|
||||||
/**************************************************************************
|
/**************************************************************************
|
||||||
|
Loading…
x
Reference in New Issue
Block a user