Commit 9309fae9 authored by andrey@lmy004's avatar andrey@lmy004

WL#3337 (Events new architecture)

5th cut, moved DB related code to Event_db_repository and
updated accordingly the remanining code.
Moved change/restore_security_context() to class THD
Removed events_priv.h
Next step is to reorganize create/update_event() and parsing for them.
But probably some other refactoring could be done in the meanwhile.
The changes so far pass the test suite.
parent 0c439c9f
...@@ -64,7 +64,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \ ...@@ -64,7 +64,7 @@ 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_data_objects.h \ sql_plugin.h authors.h sql_partition.h event_data_objects.h \
event_queue.h event_db_repository.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 \
......
...@@ -16,12 +16,15 @@ ...@@ -16,12 +16,15 @@
#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_data_objects.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 *
Event_parse_data::new_instance(THD *thd) Event_parse_data::new_instance(THD *thd)
{ {
...@@ -733,29 +736,29 @@ Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table) ...@@ -733,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);
...@@ -772,27 +775,27 @@ Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table) ...@@ -772,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;
...@@ -800,22 +803,22 @@ Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table) ...@@ -800,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));
...@@ -823,20 +826,20 @@ Event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table) ...@@ -823,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:
...@@ -1277,6 +1280,7 @@ Event_timed::mark_last_executed(THD *thd) ...@@ -1277,6 +1280,7 @@ Event_timed::mark_last_executed(THD *thd)
} }
/* /*
Drops the event Drops the event
...@@ -1299,7 +1303,8 @@ Event_timed::drop(THD *thd) ...@@ -1299,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, dbname, name, false, &tmp)); DBUG_RETURN(Events::get_instance()->
db_repository.drop_event(thd, dbname, name, false, &tmp));
} }
...@@ -1336,7 +1341,7 @@ Event_timed::update_fields(THD *thd) ...@@ -1336,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;
...@@ -1352,15 +1357,15 @@ Event_timed::update_fields(THD *thd) ...@@ -1352,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;
} }
...@@ -1630,7 +1635,7 @@ Event_timed::compile(THD *thd, MEM_ROOT *mem_root) ...@@ -1630,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);
...@@ -1669,7 +1674,7 @@ Event_timed::compile(THD *thd, MEM_ROOT *mem_root) ...@@ -1669,7 +1674,7 @@ Event_timed::compile(THD *thd, MEM_ROOT *mem_root)
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;
...@@ -1870,23 +1875,6 @@ event_timed_db_equal(Event_timed *et, LEX_STRING *db) ...@@ -1870,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
......
...@@ -40,9 +40,35 @@ ...@@ -40,9 +40,35 @@
#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 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
{ {
Event_timed(const Event_timed &); /* Prevent use of these */ Event_timed(const Event_timed &); /* Prevent use of these */
...@@ -296,4 +322,10 @@ class Event_parse_data : public Sql_alloc ...@@ -296,4 +322,10 @@ class Event_parse_data : public Sql_alloc
}; };
class Event_queue_element : public Event_timed
{
};
#endif /* _EVENT_DATA_OBJECTS_H_ */ #endif /* _EVENT_DATA_OBJECTS_H_ */
This diff is collapsed.
...@@ -16,5 +16,87 @@ ...@@ -16,5 +16,87 @@
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 */
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);
class Event_queue_element;
class Event_db_repository
{
public:
Event_db_repository(){}
~Event_db_repository(){}
int
init_repository();
void
deinit_repository();
int
open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
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);
private:
int
drop_events_by_field(THD *thd, enum enum_events_table_field field,
LEX_STRING field_value);
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_ */ #endif /* _EVENT_DB_REPOSITORY_H_ */
...@@ -15,10 +15,10 @@ ...@@ -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_data_objects.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) ...@@ -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() ...@@ -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() ...@@ -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() ...@@ -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) ...@@ -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"));
...@@ -904,12 +905,12 @@ Event_scheduler::drop_event(THD *thd, sp_name *name) ...@@ -904,12 +905,12 @@ Event_scheduler::drop_event(THD *thd, sp_name *name)
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;
...@@ -947,7 +948,7 @@ Event_scheduler::update_event(THD *thd, Event_timed *et, ...@@ -947,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"));
...@@ -961,7 +962,7 @@ Event_scheduler::update_event(THD *thd, Event_timed *et, ...@@ -961,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 ???
...@@ -1111,11 +1112,11 @@ Event_scheduler::find_event(sp_name *name, bool remove_from_q) ...@@ -1111,11 +1112,11 @@ Event_scheduler::find_event(sp_name *name, 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())
{ {
...@@ -1124,7 +1125,7 @@ Event_scheduler::drop_matching_events(THD *thd, LEX_STRING *pattern, ...@@ -1124,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
...@@ -1179,7 +1180,7 @@ Event_scheduler::drop_matching_events(THD *thd, LEX_STRING *pattern, ...@@ -1179,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");
...@@ -1187,7 +1188,6 @@ Event_scheduler::drop_schema_events(THD *thd, LEX_STRING *schema) ...@@ -1187,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);
...@@ -1713,7 +1713,7 @@ Event_scheduler::stop_all_running_events(THD *thd) ...@@ -1713,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;
...@@ -1778,7 +1778,7 @@ Event_scheduler::stop() ...@@ -1778,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)
{ {
...@@ -2116,59 +2116,6 @@ Event_scheduler::events_count() ...@@ -2116,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);
}
/* /*
...@@ -2212,7 +2159,7 @@ Event_scheduler::load_events_from_db(THD *thd) ...@@ -2212,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= Events::get_instance()->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);
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
class sp_name; 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*);
...@@ -31,17 +32,6 @@ events_shutdown(); ...@@ -31,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
{ {
...@@ -66,10 +56,10 @@ class Event_scheduler ...@@ -66,10 +56,10 @@ class Event_scheduler
/* 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);
...@@ -78,10 +68,10 @@ class Event_scheduler ...@@ -78,10 +68,10 @@ class Event_scheduler
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
...@@ -92,20 +82,24 @@ class Event_scheduler ...@@ -92,20 +82,24 @@ class Event_scheduler
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();
...@@ -156,14 +150,11 @@ class Event_scheduler ...@@ -156,14 +150,11 @@ class Event_scheduler
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
...@@ -230,6 +221,8 @@ class Event_scheduler ...@@ -230,6 +221,8 @@ class Event_scheduler
/* 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;
......
This diff is collapsed.
...@@ -20,74 +20,91 @@ class sp_name; ...@@ -20,74 +20,91 @@ class sp_name;
class Event_timed; class Event_timed;
class Event_parse_data; class Event_parse_data;
#include "event_db_repository.h"
/* 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
{
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 static int
init();
static void
deinit();
static void
init_mutexes();
static void
destroy_mutexes();
static Events*
get_instance();
int
create_event(THD *thd, Event_timed *et, Event_parse_data *parse_data, create_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
uint create_options, uint *rows_affected); uint create_options, uint *rows_affected);
static int int
update_event(THD *thd, Event_timed *et, Event_parse_data *parse_data, update_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
sp_name *new_name, uint *rows_affected); sp_name *new_name, uint *rows_affected);
static int int
drop_event(THD *thd, sp_name *name, bool drop_if_exists, uint *rows_affected); drop_event(THD *thd, sp_name *name, bool drop_if_exists, uint *rows_affected);
static int 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 int
drop_schema_events(THD *thd, char *db); drop_schema_events(THD *thd, char *db);
static int int
dump_internal_status(THD *thd); dump_internal_status(THD *thd);
static int Event_db_repository db_repository;
init();
static void private:
shutdown(); /* Singleton DP is used */
Events(){}
static void ~Events(){}
init_mutexes();
static void /* Singleton instance */
destroy_mutexes(); static Events singleton;
private:
/* Prevent use of these */ /* Prevent use of these */
Events(const Events &); Events(const Events &);
void operator=(Events &); void operator=(Events &);
......
#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;
class sp_name;
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, LEX_STRING db, LEX_STRING name, 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);
/* Compares only the name part of the identifier */
bool
event_timed_name_equal(sp_name *name, LEX_STRING *event_name);
/* 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);
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_ */
...@@ -886,7 +886,7 @@ static void close_connections(void) ...@@ -886,7 +886,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::deinit();
end_slave(); end_slave();
if (thread_count) if (thread_count)
......
...@@ -3891,7 +3891,7 @@ byte *sys_var_thd_dbug::value_ptr(THD *thd, enum_var_type type, LEX_STRING *b) ...@@ -3891,7 +3891,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");
......
...@@ -2048,6 +2048,63 @@ bool Security_context::set_user(char *user_arg) ...@@ -2048,6 +2048,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 @@ class THD :public Statement, ...@@ -869,6 +869,14 @@ class THD :public Statement,
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) ...@@ -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()
......
...@@ -3847,12 +3847,13 @@ mysql_execute_command(THD *thd) ...@@ -3847,12 +3847,13 @@ mysql_execute_command(THD *thd)
switch (lex->sql_command) { switch (lex->sql_command) {
case SQLCOM_CREATE_EVENT: case SQLCOM_CREATE_EVENT:
res= Events::create_event(thd, lex->et, lex->event_parse_data, 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->event_parse_data, res= Events::get_instance()->
update_event(thd, lex->et, lex->event_parse_data,
lex->spname, &rows_affected); lex->spname, &rows_affected);
break; break;
default:; default:;
...@@ -3895,7 +3896,7 @@ mysql_execute_command(THD *thd) ...@@ -3895,7 +3896,7 @@ mysql_execute_command(THD *thd)
} }
if (lex->sql_command == SQLCOM_SHOW_CREATE_EVENT) if (lex->sql_command == SQLCOM_SHOW_CREATE_EVENT)
res= Events::show_create_event(thd, lex->spname); res= Events::get_instance()->show_create_event(thd, lex->spname);
else else
{ {
uint rows_affected= 1; uint rows_affected= 1;
...@@ -3904,7 +3905,8 @@ mysql_execute_command(THD *thd) ...@@ -3904,7 +3905,8 @@ mysql_execute_command(THD *thd)
res= -1; res= -1;
break; break;
} }
if (!(res= Events::drop_event(thd, lex->spname, lex->drop_if_exists, if (!(res= Events::get_instance()->drop_event(thd, lex->spname,
lex->drop_if_exists,
&rows_affected))) &rows_affected)))
send_ok(thd, rows_affected); send_ok(thd, rows_affected);
} }
...@@ -3913,7 +3915,7 @@ mysql_execute_command(THD *thd) ...@@ -3913,7 +3915,7 @@ mysql_execute_command(THD *thd)
#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
......
...@@ -4324,7 +4324,7 @@ int events_table_index_read_for_db(THD *thd, TABLE *schema_table, ...@@ -4324,7 +4324,7 @@ int events_table_index_read_for_db(THD *thd, TABLE *schema_table,
DBUG_PRINT("info", ("Using prefix scanning on PK")); DBUG_PRINT("info", ("Using prefix scanning on PK"));
event_table->file->ha_index_init(0, 1); event_table->file->ha_index_init(0, 1);
event_table->field[Events::FIELD_DB]-> event_table->field[ET_FIELD_DB]->
store(thd->lex->select_lex.db, strlen(thd->lex->select_lex.db), scs); store(thd->lex->select_lex.db, strlen(thd->lex->select_lex.db), scs);
key_info= event_table->key_info; key_info= event_table->key_info;
key_len= key_info->key_part[0].store_length; key_len= key_info->key_part[0].store_length;
...@@ -4443,7 +4443,7 @@ int fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */) ...@@ -4443,7 +4443,7 @@ int fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
thd->lex->select_lex.db:"(null)")); thd->lex->select_lex.db:"(null)"));
thd->reset_n_backup_open_tables_state(&backup); thd->reset_n_backup_open_tables_state(&backup);
if (Events::open_event_table(thd, TL_READ, &event_table)) if (Events::get_instance()->open_event_table(thd, TL_READ, &event_table))
{ {
sql_print_error("Table mysql.event is damaged."); sql_print_error("Table mysql.event is damaged.");
thd->restore_backup_open_tables_state(&backup); thd->restore_backup_open_tables_state(&backup);
......
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