Commit f9245408 authored by andrey@lmy004's avatar andrey@lmy004

Merge

parents 632c6e60 98d10477
......@@ -1778,3 +1778,8 @@ vio/viotest-sslconnect.cpp
vio/viotest.cpp
zlib/*.ds?
zlib/*.vcproj
libmysql/viosocket.o.6WmSJk
libmysqld/event_data_objects.cc
libmysqld/event_db_repository.cc
libmysqld/event_queue.cc
server-tools/instance-manager/net_serv.cc
......@@ -68,7 +68,8 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
spatial.cc gstream.cc sql_help.cc tztime.cc sql_cursor.cc \
sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \
parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \
event_scheduler.cc events.cc event_timed.cc \
event_scheduler.cc events.cc event_data_objects.cc \
event_queue.cc event_db_repository.cc \
rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \
sql_tablespace.cc \
rpl_injector.cc my_user.c partition_info.cc
......
......@@ -85,13 +85,25 @@ SHOW EVENTS;
Db Name Definer Type Execute at Interval value Interval field Starts Ends Status
events_test event_starts_test root@localhost RECURRING NULL 20 SECOND # # ENABLED
DROP EVENT event_starts_test;
create table test_nested(a int);
create event e_43 on schedule every 1 second do set @a = 5;
set global event_scheduler = 1;
alter event e_43 do alter event e_43 do set @a = 4;
ERROR HY000: Recursivity of EVENT DDL statements is forbidden when body is present
alter event e_43 do
begin
alter event e_43 on schedule every 5 minute;
insert into test_nested values(1);
end|
set global event_scheduler = 1;
select db, name, body, status, interval_field, interval_value from mysql.event;
db name body status interval_field interval_value
events_test e_43 set @a = 4 ENABLED SECOND 1
events_test e_43 begin
alter event e_43 on schedule every 5 minute;
insert into test_nested values(1);
end ENABLED MINUTE 5
drop event e_43;
drop table test_nested;
"Let's check whether we can use non-qualified names"
create table non_qualif(a int);
create event non_qualif_ev on schedule every 10 minute do insert into non_qualif values (800219);
......@@ -358,7 +370,7 @@ root localhost events_test Connect User lock select get_lock("test_lock2_1", 20)
drop event закачка21;
create table t_16 (s1 int);
create trigger t_16_bi before insert on t_16 for each row create event e_16 on schedule every 1 second do set @a=5;
ERROR HY000: Explicit or implicit commit is not allowed in stored function or trigger.
ERROR HY000: Recursivity of EVENT DDL statements is forbidden when body is present
drop table t_16;
create event white_space
on schedule every 10 hour
......
......@@ -17,18 +17,7 @@ DROP EVENT ДОЛЕН_регистър_утф8;
SET NAMES latin1;
set @a=3;
CREATE PROCEDURE p_16 () CREATE EVENT e_16 ON SCHEDULE EVERY @a SECOND DO SET @a=5;
call p_16();
"Here we used to crash!"
call p_16();
ERROR HY000: Event 'e_16' already exists
call p_16();
ERROR HY000: Event 'e_16' already exists
DROP EVENT e_16;
CALL p_16();
CALL p_16();
ERROR HY000: Event 'e_16' already exists
DROP PROCEDURE p_16;
DROP EVENT e_16;
ERROR HY000: Recursivity of EVENT DDL statements is forbidden when body is present
create event e_55 on schedule at 99990101000000 do drop table t;
ERROR HY000: Incorrect AT value: '99990101000000'
create event e_55 on schedule every 10 hour starts 99990101000000 do drop table t;
......
......@@ -81,14 +81,23 @@ SHOW EVENTS;
DROP EVENT event_starts_test;
#
#
create table test_nested(a int);
create event e_43 on schedule every 1 second do set @a = 5;
set global event_scheduler = 1;
--sleep 2
--error 1562
alter event e_43 do alter event e_43 do set @a = 4;
--sleep 2
delimiter |;
alter event e_43 do
begin
alter event e_43 on schedule every 5 minute;
insert into test_nested values(1);
end|
delimiter ;|
set global event_scheduler = 1;
--sleep 1
select db, name, body, status, interval_field, interval_value from mysql.event;
drop event e_43;
--sleep 1
drop table test_nested;
--echo "Let's check whether we can use non-qualified names"
create table non_qualif(a int);
......@@ -315,7 +324,7 @@ drop event закачка21;
# Bug #16410 Events: CREATE EVENT is legal in a CREATE TRIGGER statement
#
create table t_16 (s1 int);
--error 1422
--error 1562
create trigger t_16_bi before insert on t_16 for each row create event e_16 on schedule every 1 second do set @a=5;
drop table t_16;
#
......
......@@ -30,19 +30,8 @@ SET NAMES latin1;
# START - BUG#16408: Events: crash for an event in a procedure
#
set @a=3;
--error 1562
CREATE PROCEDURE p_16 () CREATE EVENT e_16 ON SCHEDULE EVERY @a SECOND DO SET @a=5;
call p_16();
--echo "Here we used to crash!"
--error ER_EVENT_ALREADY_EXISTS
call p_16();
--error ER_EVENT_ALREADY_EXISTS
call p_16();
DROP EVENT e_16;
CALL p_16();
--error ER_EVENT_ALREADY_EXISTS
CALL p_16();
DROP PROCEDURE p_16;
DROP EVENT e_16;
#
# END - BUG#16408: Events: crash for an event in a procedure
#
......
......@@ -51,7 +51,8 @@ ADD_EXECUTABLE(mysqld ../sql-common/client.c derror.cc des_key_file.cc
sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc
sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc
time.cc tztime.cc uniques.cc unireg.cc item_xmlfunc.cc
rpl_tblmap.cc sql_binlog.cc event_scheduler.cc event_timed.cc
rpl_tblmap.cc sql_binlog.cc event_scheduler.cc event_data_objects.cc
event_queue.cc event_db_repository.cc
sql_tablespace.cc events.cc ../sql-common/my_user.c
partition_info.cc rpl_injector.cc
${PROJECT_SOURCE_DIR}/sql/sql_yacc.cc
......
......@@ -64,8 +64,9 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
tztime.h my_decimal.h\
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
parse_file.h sql_view.h sql_trigger.h \
sql_array.h sql_cursor.h events.h events_priv.h \
sql_plugin.h authors.h sql_partition.h event_timed.h \
sql_array.h sql_cursor.h events.h \
sql_plugin.h authors.h sql_partition.h event_data_objects.h \
event_queue.h event_db_repository.h \
partition_info.h partition_element.h event_scheduler.h \
contributors.h
mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
......@@ -104,7 +105,8 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
tztime.cc my_time.c my_user.c my_decimal.cc\
sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
sp_cache.cc parse_file.cc sql_trigger.cc \
event_scheduler.cc events.cc event_timed.cc \
event_scheduler.cc events.cc event_data_objects.cc \
event_queue.cc event_db_repository.cc \
sql_plugin.cc sql_binlog.cc \
sql_builtin.cc sql_tablespace.cc partition_info.cc
......
#ifndef _EVENT_TIMED_H_
#define _EVENT_TIMED_H_
#ifndef _EVENT_DATA_OBJECTS_H_
#define _EVENT_DATA_OBJECTS_H_
/* Copyright (C) 2004-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
......@@ -40,7 +40,34 @@
#define EVENT_FREE_WHEN_FINISHED (1L << 2)
#define EVENT_EXEC_STARTED 0
#define EVENT_EXEC_ALREADY_EXEC 1
#define EVENT_EXEC_CANT_FORK 2
class sp_head;
class Sql_alloc;
class Event_timed;
/* Compares only the schema part of the identifier */
bool
event_timed_db_equal(Event_timed *et, LEX_STRING *db);
/* Compares the whole identifier*/
bool
event_timed_identifier_equal(Event_timed *a, Event_timed *b);
/* Compares only the schema part of the identifier */
bool
event_timed_db_equal(sp_name *name, LEX_STRING *db);
/* Compares the whole identifier*/
bool
event_timed_identifier_equal(sp_name *a, Event_timed *b);
class Event_timed
{
......@@ -213,5 +240,92 @@ class Event_timed
void
set_thread_id(ulong tid) { thread_id= tid; }
};
#endif /* _EVENT_H_ */
class Event_parse_data : public Sql_alloc
{
Event_parse_data(const Event_parse_data &); /* Prevent use of these */
void operator=(Event_parse_data &);
public:
enum enum_status
{
ENABLED = 1,
DISABLED
};
enum enum_on_completion
{
ON_COMPLETION_DROP = 1,
ON_COMPLETION_PRESERVE
};
enum enum_on_completion on_completion;
enum enum_status status;
const uchar *body_begin;
LEX_STRING dbname;
LEX_STRING name;
LEX_STRING body;
LEX_STRING definer_user;
LEX_STRING definer_host;
LEX_STRING definer;// combination of user and host
LEX_STRING comment;
Item* item_starts;
Item* item_ends;
Item* item_execute_at;
TIME starts;
TIME ends;
TIME execute_at;
my_bool starts_null;
my_bool ends_null;
my_bool execute_at_null;
sp_name *identifier;
Item* item_expression;
longlong expression;
interval_type interval;
static Event_parse_data *
new_instance(THD *thd);
Event_parse_data();
~Event_parse_data();
int
init_definer(THD *thd);
int
init_execute_at(THD *thd, Item *expr);
int
init_interval(THD *thd, Item *expr, interval_type new_interval);
void
init_name(THD *thd, sp_name *spn);
int
init_starts(THD *thd, Item *starts);
int
init_ends(THD *thd, Item *ends);
void
init_body(THD *thd);
void
init_comment(THD *thd, LEX_STRING *set_comment);
};
class Event_queue_element : public Event_timed
{
};
#endif /* _EVENT_DATA_OBJECTS_H_ */
This diff is collapsed.
#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_ */
#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
......@@ -16,64 +14,6 @@
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_ */
#include "mysql_priv.h"
#include "event_queue.h"
#include "event_data_objects.h"
#ifndef _EVENT_QUEUE_H_
#define _EVENT_QUEUE_H_
/* Copyright (C) 2004-2006 MySQL AB
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#endif /* _EVENT_QUEUE_H_ */
......@@ -15,10 +15,10 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysql_priv.h"
#include "events_priv.h"
#include "events.h"
#include "event_timed.h"
#include "event_data_objects.h"
#include "event_scheduler.h"
#include "event_db_repository.h"
#include "sp_head.h"
/*
......@@ -574,8 +574,8 @@ event_worker_thread(void *arg)
to change the context before sending the signal. We are under
LOCK_scheduler_data being held by Event_scheduler::run() -> ::execute_top().
*/
change_security_context(thd, event->definer_user, event->definer_host,
event->dbname, &security_ctx, &save_ctx);
thd->change_security_context(event->definer_user, event->definer_host,
event->dbname, &security_ctx, &save_ctx);
DBUG_PRINT("info", ("master_access=%d db_access=%d",
thd->security_ctx->master_access, thd->security_ctx->db_access));
......@@ -687,7 +687,7 @@ Event_scheduler::get_instance()
*/
bool
Event_scheduler::init()
Event_scheduler::init(Event_db_repository *db_repo)
{
int i= 0;
bool ret= FALSE;
......@@ -695,6 +695,7 @@ Event_scheduler::init()
DBUG_PRINT("enter", ("this=%p", this));
LOCK_SCHEDULER_DATA();
db_repository= db_repo;
for (;i < COND_LAST; i++)
if (pthread_cond_init(&cond_vars[i], NULL))
{
......@@ -783,10 +784,10 @@ Event_scheduler::destroy()
OP_LOAD_ERROR Error during loading from disk
*/
enum Event_scheduler::enum_error_code
int
Event_scheduler::create_event(THD *thd, Event_timed *et, bool check_existence)
{
enum enum_error_code res;
int res;
Event_timed *et_new;
DBUG_ENTER("Event_scheduler::create_event");
DBUG_PRINT("enter", ("thd=%p et=%p lock=%p",thd,et,&LOCK_scheduler_data));
......@@ -805,7 +806,7 @@ Event_scheduler::create_event(THD *thd, Event_timed *et, bool check_existence)
}
/* We need to load the event on scheduler_root */
if (!(res= load_named_event(thd, et, &et_new)))
if (!(res= db_repository->load_named_event(thd, et, &et_new)))
{
queue_insert_safe(&queue, (byte *) et_new);
DBUG_PRINT("info", ("Sending COND_new_work"));
......@@ -833,12 +834,13 @@ Event_scheduler::create_event(THD *thd, Event_timed *et, bool check_existence)
*/
bool
Event_scheduler::drop_event(THD *thd, Event_timed *et)
Event_scheduler::drop_event(THD *thd, sp_name *name)
{
int res;
Event_timed *et_old;
DBUG_ENTER("Event_scheduler::drop_event");
DBUG_PRINT("enter", ("thd=%p et=%p lock=%p",thd,et,&LOCK_scheduler_data));
DBUG_PRINT("enter", ("thd=%p name=%p lock=%p", thd, name,
&LOCK_scheduler_data));
LOCK_SCHEDULER_DATA();
if (!is_running_or_suspended())
......@@ -848,7 +850,7 @@ Event_scheduler::drop_event(THD *thd, Event_timed *et)
DBUG_RETURN(OP_OK);
}
if (!(et_old= find_event(et, TRUE)))
if (!(et_old= find_event(name, TRUE)))
DBUG_PRINT("info", ("No such event found, probably DISABLED"));
UNLOCK_SCHEDULER_DATA();
......@@ -903,12 +905,12 @@ Event_scheduler::drop_event(THD *thd, Event_timed *et)
OP_ALREADY_EXISTS Event already in the queue
*/
enum Event_scheduler::enum_error_code
int
Event_scheduler::update_event(THD *thd, Event_timed *et,
LEX_STRING *new_schema,
LEX_STRING *new_name)
{
enum enum_error_code res;
int res= OP_OK;
Event_timed *et_old, *et_new= NULL;
LEX_STRING old_schema, old_name;
......@@ -946,7 +948,7 @@ Event_scheduler::update_event(THD *thd, Event_timed *et,
1. Error occured
2. If the replace is DISABLED, we don't load it into the queue.
*/
if (!(res= load_named_event(thd, et, &et_new)))
if (!(res= db_repository->load_named_event(thd, et, &et_new)))
{
queue_insert_safe(&queue, (byte *) et_new);
DBUG_PRINT("info", ("Sending COND_new_work"));
......@@ -960,7 +962,7 @@ Event_scheduler::update_event(THD *thd, Event_timed *et,
et->dbname= old_schema;
et->name= old_name;
}
DBUG_PRINT("info", ("res=%d", res));
UNLOCK_SCHEDULER_DATA();
/*
Andrey: Is this comment still truthful ???
......@@ -1049,6 +1051,48 @@ Event_scheduler::find_event(Event_timed *etn, bool remove_from_q)
}
/*
Searches for an event in the scheduler queue
SYNOPSIS
Event_scheduler::find_event()
name The event to find
comparator The function to use for comparing
remove_from_q If found whether to remove from the Q
RETURN VALUE
NULL Not found
otherwise Address
NOTE
The caller should do the locking also the caller is responsible for
actual signalling in case an event is removed from the queue
(signalling COND_new_work for instance).
*/
Event_timed *
Event_scheduler::find_event(sp_name *name, bool remove_from_q)
{
uint i;
DBUG_ENTER("Event_scheduler::find_event");
for (i= 0; i < queue.elements; ++i)
{
Event_timed *et= (Event_timed *) queue_element(&queue, i);
DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?", name->m_db.str, name->m_name.str,
et->dbname.str, et->name.str));
if (event_timed_identifier_equal(name, et))
{
if (remove_from_q)
queue_remove(&queue, i);
DBUG_RETURN(et);
}
}
DBUG_RETURN(NULL);
}
/*
Drops all events from the in-memory queue and disk that match
certain pattern evaluated by a comparator function
......@@ -1068,11 +1112,11 @@ Event_scheduler::find_event(Event_timed *etn, bool remove_from_q)
*/
void
Event_scheduler::drop_matching_events(THD *thd, LEX_STRING *pattern,
Event_scheduler::drop_matching_events(THD *thd, LEX_STRING pattern,
bool (*comparator)(Event_timed *,LEX_STRING *))
{
DBUG_ENTER("Event_scheduler::drop_matching_events");
DBUG_PRINT("enter", ("pattern=%*s state=%d", pattern->length, pattern->str,
DBUG_PRINT("enter", ("pattern=%*s state=%d", pattern.length, pattern.str,
state));
if (is_running_or_suspended())
{
......@@ -1081,7 +1125,7 @@ Event_scheduler::drop_matching_events(THD *thd, LEX_STRING *pattern,
{
Event_timed *et= (Event_timed *) queue_element(&queue, i);
DBUG_PRINT("info", ("[%s.%s]?", et->dbname.str, et->name.str));
if (comparator(et, pattern))
if (comparator(et, &pattern))
{
/*
The queue is ordered. If we remove an element, then all elements after
......@@ -1136,7 +1180,7 @@ Event_scheduler::drop_matching_events(THD *thd, LEX_STRING *pattern,
*/
int
Event_scheduler::drop_schema_events(THD *thd, LEX_STRING *schema)
Event_scheduler::drop_schema_events(THD *thd, LEX_STRING schema)
{
int ret;
DBUG_ENTER("Event_scheduler::drop_schema_events");
......@@ -1144,7 +1188,6 @@ Event_scheduler::drop_schema_events(THD *thd, LEX_STRING *schema)
if (is_running_or_suspended())
drop_matching_events(thd, schema, event_timed_db_equal);
ret= db_drop_events_from_table(thd, schema);
UNLOCK_SCHEDULER_DATA();
DBUG_RETURN(ret);
......@@ -1670,7 +1713,7 @@ Event_scheduler::stop_all_running_events(THD *thd)
The caller must have acquited LOCK_scheduler_data.
*/
enum Event_scheduler::enum_error_code
int
Event_scheduler::stop()
{
THD *thd= current_thd;
......@@ -1735,7 +1778,7 @@ Event_scheduler::stop()
OP_OK OK
*/
enum Event_scheduler::enum_error_code
int
Event_scheduler::suspend_or_resume(
enum Event_scheduler::enum_suspend_or_resume action)
{
......@@ -2073,59 +2116,6 @@ Event_scheduler::events_count()
}
/*
Looks for a named event in mysql.event and then loads it from
the table, compiles and inserts it into the cache.
SYNOPSIS
Event_scheduler::load_named_event()
thd THD
etn The name of the event to load and compile on scheduler's root
etn_new The loaded event
RETURN VALUE
NULL Error during compile or the event is non-enabled.
otherwise Address
*/
enum Event_scheduler::enum_error_code
Event_scheduler::load_named_event(THD *thd, Event_timed *etn, Event_timed **etn_new)
{
int ret= 0;
MEM_ROOT *tmp_mem_root;
Event_timed *et_loaded= NULL;
Open_tables_state backup;
DBUG_ENTER("Event_scheduler::load_and_compile_event");
DBUG_PRINT("enter",("thd=%p name:%*s",thd, etn->name.length, etn->name.str));
thd->reset_n_backup_open_tables_state(&backup);
/* No need to use my_error() here because db_find_event() has done it */
{
sp_name spn(etn->dbname, etn->name);
ret= db_find_event(thd, &spn, &et_loaded, NULL, &scheduler_root);
}
thd->restore_backup_open_tables_state(&backup);
/* In this case no memory was allocated so we don't need to clean */
if (ret)
DBUG_RETURN(OP_LOAD_ERROR);
if (et_loaded->status != Event_timed::ENABLED)
{
/*
We don't load non-enabled events.
In db_find_event() `et_new` was allocated on the heap and not on
scheduler_root therefore we delete it here.
*/
delete et_loaded;
DBUG_RETURN(OP_DISABLED_EVENT);
}
et_loaded->compute_next_execution_time();
*etn_new= et_loaded;
DBUG_RETURN(OP_OK);
}
/*
......@@ -2169,7 +2159,7 @@ Event_scheduler::load_events_from_db(THD *thd)
DBUG_RETURN(EVEX_GENERAL_ERROR);
}
if ((ret= Events::open_event_table(thd, TL_READ, &table)))
if ((ret= db_repository->open_event_table(thd, TL_READ, &table)))
{
sql_print_error("SCHEDULER: Table mysql.event is damaged. Can not open.");
DBUG_RETURN(EVEX_OPEN_TABLE_FAILED);
......
......@@ -16,7 +16,9 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
class sp_name;
class Event_timed;
class Event_db_repository;
class THD;
typedef bool * (*event_timed_identifier_comparator)(Event_timed*, Event_timed*);
......@@ -30,17 +32,6 @@ events_shutdown();
class Event_scheduler
{
public:
/* Return codes */
enum enum_error_code
{
OP_OK= 0,
OP_NOT_RUNNING,
OP_CANT_KILL,
OP_CANT_INIT,
OP_DISABLED_EVENT,
OP_LOAD_ERROR,
OP_ALREADY_EXISTS
};
enum enum_state
{
......@@ -65,22 +56,22 @@ class Event_scheduler
/* Methods for queue management follow */
enum enum_error_code
int
create_event(THD *thd, Event_timed *et, bool check_existence);
enum enum_error_code
int
update_event(THD *thd, Event_timed *et, LEX_STRING *new_schema,
LEX_STRING *new_name);
bool
drop_event(THD *thd, Event_timed *et);
drop_event(THD *thd, sp_name *name);
int
drop_schema_events(THD *thd, LEX_STRING *schema);
drop_schema_events(THD *thd, LEX_STRING schema);
int
drop_user_events(THD *thd, LEX_STRING *definer, uint *dropped_num)
drop_user_events(THD *thd, LEX_STRING *definer)
{ DBUG_ASSERT(0); return 0;}
uint
......@@ -91,20 +82,24 @@ class Event_scheduler
bool
start();
enum enum_error_code
int
stop();
bool
start_suspended();
/*
Need to be public because has to be called from the function
passed to pthread_create.
*/
bool
run(THD *thd);
enum enum_error_code
int
suspend_or_resume(enum enum_suspend_or_resume action);
bool
init();
init(Event_db_repository *db_repo);
void
destroy();
......@@ -136,6 +131,9 @@ class Event_scheduler
Event_timed *
find_event(Event_timed *etn, bool remove_from_q);
Event_timed *
find_event(sp_name *name, bool remove_from_q);
uint
workers_count();
......@@ -152,14 +150,11 @@ class Event_scheduler
void
stop_all_running_events(THD *thd);
enum enum_error_code
load_named_event(THD *thd, Event_timed *etn, Event_timed **etn_new);
int
load_events_from_db(THD *thd);
void
drop_matching_events(THD *thd, LEX_STRING *pattern,
drop_matching_events(THD *thd, LEX_STRING pattern,
bool (*)(Event_timed *,LEX_STRING *));
bool
......@@ -226,6 +221,8 @@ class Event_scheduler
/* The MEM_ROOT of the object */
MEM_ROOT scheduler_root;
Event_db_repository *db_repository;
/* The sorted queue with the Event_timed objects */
QUEUE queue;
......
This diff is collapsed.
......@@ -16,78 +16,96 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
class sp_name;
class Event_timed;
class Event_parse_data;
class Event_db_repository;
/* Return codes */
enum enum_events_error_code
{
OP_OK= 0,
OP_NOT_RUNNING,
OP_CANT_KILL,
OP_CANT_INIT,
OP_DISABLED_EVENT,
OP_LOAD_ERROR,
OP_ALREADY_EXISTS
};
int
sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs);
class Events
{
public:
/*
Quite NOT the best practice and will be removed once
Event_timed::drop() and Event_timed is fixed not do drop directly
or other scheme will be found.
*/
friend class Event_timed;
static ulong opt_event_scheduler;
static TYPELIB opt_typelib;
enum enum_table_field
{
FIELD_DB = 0,
FIELD_NAME,
FIELD_BODY,
FIELD_DEFINER,
FIELD_EXECUTE_AT,
FIELD_INTERVAL_EXPR,
FIELD_TRANSIENT_INTERVAL,
FIELD_CREATED,
FIELD_MODIFIED,
FIELD_LAST_EXECUTED,
FIELD_STARTS,
FIELD_ENDS,
FIELD_STATUS,
FIELD_ON_COMPLETION,
FIELD_SQL_MODE,
FIELD_COMMENT,
FIELD_COUNT /* a cool trick to count the number of fields :) */
};
int
init();
void
deinit();
static int
create_event(THD *thd, Event_timed *et, uint create_options,
uint *rows_affected);
void
init_mutexes();
void
destroy_mutexes();
static int
update_event(THD *thd, Event_timed *et, sp_name *new_name,
uint *rows_affected);
static Events*
get_instance();
static int
drop_event(THD *thd, Event_timed *et, bool drop_if_exists,
uint *rows_affected);
int
create_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
uint create_options, uint *rows_affected);
static int
int
update_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
sp_name *new_name, uint *rows_affected);
int
drop_event(THD *thd, sp_name *name, bool drop_if_exists, uint *rows_affected);
int
drop_schema_events(THD *thd, char *db);
int
open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
static int
int
show_create_event(THD *thd, sp_name *spn);
/* Needed for both SHOW CREATE EVENT and INFORMATION_SCHEMA */
static int
reconstruct_interval_expression(String *buf, interval_type interval,
longlong expression);
static int
drop_schema_events(THD *thd, char *db);
fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */);
static int
int
dump_internal_status(THD *thd);
static int
init();
static void
shutdown();
static void
init_mutexes();
static void
destroy_mutexes();
Event_db_repository *db_repository;
private:
/* Singleton DP is used */
Events(){}
~Events(){}
/* Singleton instance */
static Events singleton;
/* Prevent use of these */
Events(const Events &);
void operator=(Events &);
......
......@@ -883,7 +883,7 @@ static void close_connections(void)
}
(void) pthread_mutex_unlock(&LOCK_thread_count); // For unlink from list
Events::shutdown();
Events::get_instance()->deinit();
end_slave();
if (thread_count)
......@@ -1321,7 +1321,7 @@ static void clean_up_mutexes()
(void) pthread_mutex_destroy(&LOCK_bytes_sent);
(void) pthread_mutex_destroy(&LOCK_bytes_received);
(void) pthread_mutex_destroy(&LOCK_user_conn);
Events::destroy_mutexes();
Events::get_instance()->destroy_mutexes();
#ifdef HAVE_OPENSSL
(void) pthread_mutex_destroy(&LOCK_des_key_file);
#ifndef HAVE_YASSL
......@@ -2884,7 +2884,7 @@ static int init_thread_environment()
(void) pthread_mutex_init(&LOCK_server_started, MY_MUTEX_INIT_FAST);
(void) pthread_cond_init(&COND_server_started,NULL);
sp_cache_init();
Events::init_mutexes();
Events::get_instance()->init_mutexes();
/* Parameter for threads created for connections */
(void) pthread_attr_init(&connection_attrib);
(void) pthread_attr_setdetachstate(&connection_attrib,
......@@ -3673,7 +3673,7 @@ we force server id to 2, but this MySQL server will not act as a slave.");
if (!opt_noacl)
{
Events::init();
Events::get_instance()->init();
}
#if defined(__NT__) || defined(HAVE_SMEM)
handle_connections_methods();
......
......@@ -3892,7 +3892,7 @@ byte *sys_var_thd_dbug::value_ptr(THD *thd, enum_var_type type, LEX_STRING *b)
bool
sys_var_event_scheduler::update(THD *thd, set_var *var)
{
enum Event_scheduler::enum_error_code res;
int res;
Event_scheduler *scheduler= Event_scheduler::get_instance();
/* here start the thread if not running. */
DBUG_ENTER("sys_var_event_scheduler::update");
......
......@@ -5839,3 +5839,6 @@ ER_CANT_ACTIVATE_LOG
eng "Cannot activate '%-.64s' log."
ER_RBR_NOT_AVAILABLE
eng "The server was not built with row-based replication"
ER_EVENT_RECURSIVITY_FORBIDDEN
eng "Recursivity of EVENT DDL statements is forbidden when body is present"
......@@ -2073,6 +2073,63 @@ bool Security_context::set_user(char *user_arg)
return user == 0;
}
/*
Switches the security context
SYNOPSIS
THD::change_security_context()
user The user
host The host of the user
db The schema for which the security_ctx will be loaded
s_ctx Security context to load state into
backup Where to store the old context
RETURN VALUE
FALSE OK
TRUE Error (generates error too)
*/
bool
THD::change_security_context(LEX_STRING user, LEX_STRING host,
LEX_STRING db, Security_context *s_ctx,
Security_context **backup)
{
DBUG_ENTER("change_security_context");
DBUG_PRINT("info",("%s@%s@%s", user.str, host.str, db.str));
#ifndef NO_EMBEDDED_ACCESS_CHECKS
s_ctx->init();
*backup= 0;
if (acl_getroot_no_password(s_ctx, user.str, host.str, host.str, db.str))
{
my_error(ER_NO_SUCH_USER, MYF(0), user.str, host.str);
DBUG_RETURN(TRUE);
}
*backup= security_ctx;
security_ctx= s_ctx;
#endif
DBUG_RETURN(FALSE);
}
/*
Restores the security context
SYNOPSIS
restore_security_context()
thd Thread
backup Context to switch to
*/
void
THD::restore_security_context(Security_context *backup)
{
DBUG_ENTER("restore_security_context");
#ifndef NO_EMBEDDED_ACCESS_CHECKS
if (backup)
security_ctx= backup;
#endif
DBUG_VOID_RETURN;
}
/****************************************************************************
Handling of open and locked tables states.
......
......@@ -868,6 +868,14 @@ class THD :public Statement,
char *db, *catalog;
Security_context main_security_ctx;
Security_context *security_ctx;
bool
change_security_context(LEX_STRING user, LEX_STRING host,
LEX_STRING db, Security_context *s_ctx,
Security_context **backup);
void
restore_security_context(Security_context *backup);
/* remote (peer) port */
uint16 peer_port;
......
......@@ -904,7 +904,7 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
exit:
(void)sp_drop_db_routines(thd, db); /* QQ Ignore errors for now */
error= Events::drop_schema_events(thd, db);
error= Events::get_instance()->drop_schema_events(thd, db);
/*
If this database was the client's selected database, we silently change the
client's selected database to nothing (to have an empty SELECT DATABASE()
......
......@@ -28,6 +28,7 @@ class sp_pcontext;
class st_alter_tablespace;
class partition_info;
class Event_timed;
class Event_parse_data;
#ifdef MYSQL_SERVER
/*
......@@ -1017,6 +1018,7 @@ typedef struct st_lex : public Query_tables_list
st_sp_chistics sp_chistics;
Event_timed *et;
Event_parse_data *event_parse_data;
bool et_compile_phase;
bool only_view; /* used for SHOW CREATE TABLE/VIEW */
......
......@@ -27,7 +27,7 @@
#include "sp.h"
#include "sp_cache.h"
#include "events.h"
#include "event_timed.h"
#include "event_data_objects.h"
#ifdef HAVE_OPENSSL
/*
......@@ -3831,7 +3831,6 @@ mysql_execute_command(THD *thd)
}
case SQLCOM_CREATE_EVENT:
case SQLCOM_ALTER_EVENT:
case SQLCOM_DROP_EVENT:
{
uint rows_affected= 1;
DBUG_ASSERT(lex->et);
......@@ -3860,17 +3859,15 @@ mysql_execute_command(THD *thd)
switch (lex->sql_command) {
case SQLCOM_CREATE_EVENT:
res= Events::create_event(thd, lex->et,
(uint) lex->create_info.options,
&rows_affected);
res= Events::get_instance()->
create_event(thd, lex->et, lex->event_parse_data,
(uint) lex->create_info.options, &rows_affected);
break;
case SQLCOM_ALTER_EVENT:
res= Events::update_event(thd, lex->et, lex->spname,
&rows_affected);
res= Events::get_instance()->
update_event(thd, lex->et, lex->event_parse_data,
lex->spname, &rows_affected);
break;
case SQLCOM_DROP_EVENT:
res= Events::drop_event(thd, lex->et, lex->drop_if_exists,
&rows_affected);
default:;
}
DBUG_PRINT("info", ("CREATE/ALTER/DROP returned error code=%d af_rows=%d",
......@@ -3889,10 +3886,10 @@ mysql_execute_command(THD *thd)
break;
}
case SQLCOM_DROP_EVENT:
case SQLCOM_SHOW_CREATE_EVENT:
{
DBUG_ASSERT(lex->spname);
DBUG_ASSERT(lex->et);
if (! lex->spname->m_db.str)
{
my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
......@@ -3906,15 +3903,31 @@ mysql_execute_command(THD *thd)
if (lex->spname->m_name.length > NAME_LEN)
{
my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
/* this jumps to the end of the function and skips own messaging */
goto error;
}
res= Events::show_create_event(thd, lex->spname);
if (lex->sql_command == SQLCOM_SHOW_CREATE_EVENT)
res= Events::get_instance()->show_create_event(thd, lex->spname);
else
{
uint rows_affected= 1;
if (end_active_trans(thd))
{
res= -1;
break;
}
if (!(res= Events::get_instance()->drop_event(thd, lex->spname,
lex->drop_if_exists,
&rows_affected)))
send_ok(thd, rows_affected);
}
break;
}
#ifndef DBUG_OFF
case SQLCOM_SHOW_SCHEDULER_STATUS:
{
res= Events::dump_internal_status(thd);
res= Events::get_instance()->dump_internal_status(thd);
break;
}
#endif
......
......@@ -27,7 +27,7 @@
#include "authors.h"
#include "contributors.h"
#include "events.h"
#include "event_timed.h"
#include "event_data_objects.h"
#include <my_dir.h>
#ifdef WITH_PARTITION_STORAGE_ENGINE
......@@ -4166,7 +4166,7 @@ extern LEX_STRING interval_type_to_name[];
1 Error
*/
static int
int
copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
{
const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS;
......@@ -4301,183 +4301,6 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
}
/*
Performs an index scan of event_table (mysql.event) and fills schema_table.
Synopsis
events_table_index_read_for_db()
thd Thread
schema_table The I_S.EVENTS table
event_table The event table to use for loading (mysql.event)
Returns
0 OK
1 Error
*/
static
int events_table_index_read_for_db(THD *thd, TABLE *schema_table,
TABLE *event_table)
{
int ret=0;
CHARSET_INFO *scs= system_charset_info;
KEY *key_info;
uint key_len;
byte *key_buf= NULL;
LINT_INIT(key_buf);
DBUG_ENTER("schema_events_do_index_scan");
DBUG_PRINT("info", ("Using prefix scanning on PK"));
event_table->file->ha_index_init(0, 1);
event_table->field[Events::FIELD_DB]->
store(thd->lex->select_lex.db, strlen(thd->lex->select_lex.db), scs);
key_info= event_table->key_info;
key_len= key_info->key_part[0].store_length;
if (!(key_buf= (byte *)alloc_root(thd->mem_root, key_len)))
{
ret= 1;
/* don't send error, it would be done by sql_alloc_error_handler() */
}
else
{
key_copy(key_buf, event_table->record[0], key_info, key_len);
if (!(ret= event_table->file->index_read(event_table->record[0], key_buf,
key_len, HA_READ_PREFIX)))
{
DBUG_PRINT("info",("Found rows. Let's retrieve them. ret=%d", ret));
do
{
ret= copy_event_to_schema_table(thd, schema_table, event_table);
if (ret == 0)
ret= event_table->file->index_next_same(event_table->record[0],
key_buf, key_len);
} while (ret == 0);
}
DBUG_PRINT("info", ("Scan finished. ret=%d", ret));
}
event_table->file->ha_index_end();
/* ret is guaranteed to be != 0 */
if (ret == HA_ERR_END_OF_FILE || ret == HA_ERR_KEY_NOT_FOUND)
DBUG_RETURN(0);
DBUG_RETURN(1);
}
/*
Performs a table scan of event_table (mysql.event) and fills schema_table.
Synopsis
events_table_scan_all()
thd Thread
schema_table The I_S.EVENTS in memory table
event_table The event table to use for loading.
Returns
0 OK
1 Error
*/
static
int events_table_scan_all(THD *thd, TABLE *schema_table,
TABLE *event_table)
{
int ret;
READ_RECORD read_record_info;
DBUG_ENTER("schema_events_do_table_scan");
init_read_record(&read_record_info, thd, event_table, NULL, 1, 0);
/*
rr_sequential, in read_record(), returns 137==HA_ERR_END_OF_FILE,
but rr_handle_error returns -1 for that reason. Thus, read_record()
returns -1 eventually.
*/
do
{
ret= read_record_info.read_record(&read_record_info);
if (ret == 0)
ret= copy_event_to_schema_table(thd, schema_table, event_table);
}
while (ret == 0);
DBUG_PRINT("info", ("Scan finished. ret=%d", ret));
end_read_record(&read_record_info);
/* ret is guaranteed to be != 0 */
DBUG_RETURN(ret == -1? 0:1);
}
/*
Fills I_S.EVENTS with data loaded from mysql.event. Also used by
SHOW EVENTS
Synopsis
fill_schema_events()
thd Thread
tables The schema table
cond Unused
Returns
0 OK
1 Error
*/
int fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
{
TABLE *schema_table= tables->table;
TABLE *event_table= NULL;
Open_tables_state backup;
int ret= 0;
DBUG_ENTER("fill_schema_events");
/*
If it's SHOW EVENTS then thd->lex->select_lex.db is guaranteed not to
be NULL. Let's do an assert anyway.
*/
if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS)
{
DBUG_ASSERT(thd->lex->select_lex.db);
if (check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0,
is_schema_db(thd->lex->select_lex.db)))
DBUG_RETURN(1);
}
DBUG_PRINT("info",("db=%s", thd->lex->select_lex.db?
thd->lex->select_lex.db:"(null)"));
thd->reset_n_backup_open_tables_state(&backup);
if (Events::open_event_table(thd, TL_READ, &event_table))
{
sql_print_error("Table mysql.event is damaged.");
thd->restore_backup_open_tables_state(&backup);
DBUG_RETURN(1);
}
/*
1. SELECT I_S => use table scan. I_S.EVENTS does not guarantee order
thus we won't order it. OTOH, SHOW EVENTS will be
ordered.
2. SHOW EVENTS => PRIMARY KEY with prefix scanning on (db)
Reasoning: Events are per schema, therefore a scan over an index
will save use from doing a table scan and comparing
every single row's `db` with the schema which we show.
*/
if (thd->lex->sql_command == SQLCOM_SHOW_EVENTS)
ret= events_table_index_read_for_db(thd, schema_table, event_table);
else
ret= events_table_scan_all(thd, schema_table, event_table);
close_thread_tables(thd);
thd->restore_backup_open_tables_state(&backup);
DBUG_PRINT("info", ("Return code=%d", ret));
DBUG_RETURN(ret);
}
int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
DBUG_ENTER("fill_open_tables");
......@@ -5574,7 +5397,7 @@ ST_SCHEMA_TABLE schema_tables[]=
{"ENGINES", engines_fields_info, create_schema_table,
fill_schema_engines, make_old_format, 0, -1, -1, 0},
{"EVENTS", events_fields_info, create_schema_table,
fill_schema_events, make_old_format, 0, -1, -1, 0},
Events::fill_schema_events, make_old_format, 0, -1, -1, 0},
{"FILES", files_fields_info, create_schema_table,
fill_schema_files, 0, 0, -1, -1, 0},
{"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table,
......
......@@ -14,4 +14,6 @@ int store_create_info(THD *thd, TABLE_LIST *table_list, String *packet,
HA_CREATE_INFO *create_info_arg);
int view_store_create_info(THD *thd, TABLE_LIST *table, String *buff);
int copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table);
#endif /* SQL_SHOW_H */
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment