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. BitKeeper/deleted/.del-events_priv.h~2e8bce2cf35997df: Delete: sql/events_priv.h sql/Makefile.am: events_priv.h is no more sql/event_data_objects.cc: reorganize events code sql/event_data_objects.h: reorganize events code sql/event_db_repository.cc: reorganize events code sql/event_db_repository.h: reorganize events code sql/event_scheduler.cc: reorganize events code sql/event_scheduler.h: reorganize events code sql/events.cc: reorganize events code sql/events.h: reorganize events code sql/mysqld.cc: reorganize events code sql/set_var.cc: reorganize events code sql/sql_class.cc: add ::change_security_context() and restore_security_context() sql/sql_class.h: add ::change_security_context() and restore_security_context() sql/sql_db.cc: reorganize Events code sql/sql_parse.cc: reorganize Events code sql/sql_show.cc: reorganize Events code
This commit is contained in:
parent
cace147c63
commit
acefb78bc3
@ -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 @@
|
|||||||
|
|
||||||
#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)
|
|||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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)
|
|||||||
|
|
||||||
/* 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)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Drops the event
|
Drops the event
|
||||||
|
|
||||||
@ -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)
|
|||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
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)
|
|||||||
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 @@ 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;
|
||||||
@ -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 @@
|
|||||||
#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 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class Event_queue_element : public Event_timed
|
||||||
|
{
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
#endif /* _EVENT_DATA_OBJECTS_H_ */
|
#endif /* _EVENT_DATA_OBJECTS_H_ */
|
||||||
|
@ -17,3 +17,857 @@
|
|||||||
#include "mysql_priv.h"
|
#include "mysql_priv.h"
|
||||||
#include "event_db_repository.h"
|
#include "event_db_repository.h"
|
||||||
#include "event_data_objects.h"
|
#include "event_data_objects.h"
|
||||||
|
#include "sp_head.h"
|
||||||
|
#include "sp.h"
|
||||||
|
#include "events.h"
|
||||||
|
|
||||||
|
#define EVEX_DB_FIELD_LEN 64
|
||||||
|
#define EVEX_NAME_FIELD_LEN 64
|
||||||
|
|
||||||
|
|
||||||
|
time_t mysql_event_last_create_time= 0L;
|
||||||
|
|
||||||
|
static
|
||||||
|
TABLE_FIELD_W_TYPE event_table_fields[ET_FIELD_COUNT] = {
|
||||||
|
{
|
||||||
|
{(char *) STRING_WITH_LEN("db")},
|
||||||
|
{(char *) STRING_WITH_LEN("char(64)")},
|
||||||
|
{(char *) STRING_WITH_LEN("utf8")}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{(char *) STRING_WITH_LEN("name")},
|
||||||
|
{(char *) STRING_WITH_LEN("char(64)")},
|
||||||
|
{(char *) STRING_WITH_LEN("utf8")}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{(char *) STRING_WITH_LEN("body")},
|
||||||
|
{(char *) STRING_WITH_LEN("longblob")},
|
||||||
|
{NULL, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{(char *) STRING_WITH_LEN("definer")},
|
||||||
|
{(char *) STRING_WITH_LEN("char(77)")},
|
||||||
|
{(char *) STRING_WITH_LEN("utf8")}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{(char *) STRING_WITH_LEN("execute_at")},
|
||||||
|
{(char *) STRING_WITH_LEN("datetime")},
|
||||||
|
{NULL, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{(char *) STRING_WITH_LEN("interval_value")},
|
||||||
|
{(char *) STRING_WITH_LEN("int(11)")},
|
||||||
|
{NULL, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{(char *) STRING_WITH_LEN("interval_field")},
|
||||||
|
{(char *) STRING_WITH_LEN("enum('YEAR','QUARTER','MONTH','DAY',"
|
||||||
|
"'HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR',"
|
||||||
|
"'DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND',"
|
||||||
|
"'DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND',"
|
||||||
|
"'SECOND_MICROSECOND')")},
|
||||||
|
{NULL, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{(char *) STRING_WITH_LEN("created")},
|
||||||
|
{(char *) STRING_WITH_LEN("timestamp")},
|
||||||
|
{NULL, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{(char *) STRING_WITH_LEN("modified")},
|
||||||
|
{(char *) STRING_WITH_LEN("timestamp")},
|
||||||
|
{NULL, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{(char *) STRING_WITH_LEN("last_executed")},
|
||||||
|
{(char *) STRING_WITH_LEN("datetime")},
|
||||||
|
{NULL, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{(char *) STRING_WITH_LEN("starts")},
|
||||||
|
{(char *) STRING_WITH_LEN("datetime")},
|
||||||
|
{NULL, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{(char *) STRING_WITH_LEN("ends")},
|
||||||
|
{(char *) STRING_WITH_LEN("datetime")},
|
||||||
|
{NULL, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{(char *) STRING_WITH_LEN("status")},
|
||||||
|
{(char *) STRING_WITH_LEN("enum('ENABLED','DISABLED')")},
|
||||||
|
{NULL, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{(char *) STRING_WITH_LEN("on_completion")},
|
||||||
|
{(char *) STRING_WITH_LEN("enum('DROP','PRESERVE')")},
|
||||||
|
{NULL, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{(char *) STRING_WITH_LEN("sql_mode")},
|
||||||
|
{(char *) STRING_WITH_LEN("set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES',"
|
||||||
|
"'IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION',"
|
||||||
|
"'NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB',"
|
||||||
|
"'NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40',"
|
||||||
|
"'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES',"
|
||||||
|
"'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES',"
|
||||||
|
"'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER',"
|
||||||
|
"'HIGH_NOT_PRECEDENCE')")},
|
||||||
|
{NULL, 0}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
{(char *) STRING_WITH_LEN("comment")},
|
||||||
|
{(char *) STRING_WITH_LEN("char(64)")},
|
||||||
|
{(char *) STRING_WITH_LEN("utf8")}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Puts some data common to CREATE and ALTER EVENT into a row.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
evex_fill_row()
|
||||||
|
thd THD
|
||||||
|
table the row to fill out
|
||||||
|
et Event's data
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
0 - OK
|
||||||
|
EVEX_GENERAL_ERROR - bad data
|
||||||
|
EVEX_GET_FIELD_FAILED - field count does not match. table corrupted?
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Used both when an event is created and when it is altered.
|
||||||
|
*/
|
||||||
|
|
||||||
|
static int
|
||||||
|
evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update)
|
||||||
|
{
|
||||||
|
CHARSET_INFO *scs= system_charset_info;
|
||||||
|
enum enum_events_table_field field_num;
|
||||||
|
|
||||||
|
DBUG_ENTER("evex_fill_row");
|
||||||
|
|
||||||
|
DBUG_PRINT("info", ("dbname=[%s]", et->dbname.str));
|
||||||
|
DBUG_PRINT("info", ("name =[%s]", et->name.str));
|
||||||
|
DBUG_PRINT("info", ("body =[%s]", et->body.str));
|
||||||
|
|
||||||
|
if (table->field[field_num= ET_FIELD_DEFINER]->
|
||||||
|
store(et->definer.str, et->definer.length, scs))
|
||||||
|
goto err_truncate;
|
||||||
|
|
||||||
|
if (table->field[field_num= ET_FIELD_DB]->
|
||||||
|
store(et->dbname.str, et->dbname.length, scs))
|
||||||
|
goto err_truncate;
|
||||||
|
|
||||||
|
if (table->field[field_num= ET_FIELD_NAME]->
|
||||||
|
store(et->name.str, et->name.length, scs))
|
||||||
|
goto err_truncate;
|
||||||
|
|
||||||
|
/* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()*/
|
||||||
|
table->field[ET_FIELD_ON_COMPLETION]->
|
||||||
|
store((longlong)et->on_completion, true);
|
||||||
|
|
||||||
|
table->field[ET_FIELD_STATUS]->store((longlong)et->status, true);
|
||||||
|
|
||||||
|
/*
|
||||||
|
Change the SQL_MODE only if body was present in an ALTER EVENT and of course
|
||||||
|
always during CREATE EVENT.
|
||||||
|
*/
|
||||||
|
if (et->body.str)
|
||||||
|
{
|
||||||
|
table->field[ET_FIELD_SQL_MODE]->
|
||||||
|
store((longlong)thd->variables.sql_mode, true);
|
||||||
|
|
||||||
|
if (table->field[field_num= ET_FIELD_BODY]->
|
||||||
|
store(et->body.str, et->body.length, scs))
|
||||||
|
goto err_truncate;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (et->expression)
|
||||||
|
{
|
||||||
|
table->field[ET_FIELD_INTERVAL_EXPR]->set_notnull();
|
||||||
|
table->field[ET_FIELD_INTERVAL_EXPR]->
|
||||||
|
store((longlong)et->expression, true);
|
||||||
|
|
||||||
|
table->field[ET_FIELD_TRANSIENT_INTERVAL]->set_notnull();
|
||||||
|
/*
|
||||||
|
In the enum (C) intervals start from 0 but in mysql enum valid values start
|
||||||
|
from 1. Thus +1 offset is needed!
|
||||||
|
*/
|
||||||
|
table->field[ET_FIELD_TRANSIENT_INTERVAL]->
|
||||||
|
store((longlong)et->interval+1, true);
|
||||||
|
|
||||||
|
table->field[ET_FIELD_EXECUTE_AT]->set_null();
|
||||||
|
|
||||||
|
if (!et->starts_null)
|
||||||
|
{
|
||||||
|
table->field[ET_FIELD_STARTS]->set_notnull();
|
||||||
|
table->field[ET_FIELD_STARTS]->
|
||||||
|
store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!et->ends_null)
|
||||||
|
{
|
||||||
|
table->field[ET_FIELD_ENDS]->set_notnull();
|
||||||
|
table->field[ET_FIELD_ENDS]->
|
||||||
|
store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (et->execute_at.year)
|
||||||
|
{
|
||||||
|
table->field[ET_FIELD_INTERVAL_EXPR]->set_null();
|
||||||
|
table->field[ET_FIELD_TRANSIENT_INTERVAL]->set_null();
|
||||||
|
table->field[ET_FIELD_STARTS]->set_null();
|
||||||
|
table->field[ET_FIELD_ENDS]->set_null();
|
||||||
|
|
||||||
|
table->field[ET_FIELD_EXECUTE_AT]->set_notnull();
|
||||||
|
table->field[ET_FIELD_EXECUTE_AT]->
|
||||||
|
store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
DBUG_ASSERT(is_update);
|
||||||
|
/*
|
||||||
|
it is normal to be here when the action is update
|
||||||
|
this is an error if the action is create. something is borked
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
((Field_timestamp *)table->field[ET_FIELD_MODIFIED])->set_time();
|
||||||
|
|
||||||
|
if (et->comment.str)
|
||||||
|
{
|
||||||
|
if (table->field[field_num= ET_FIELD_COMMENT]->
|
||||||
|
store(et->comment.str, et->comment.length, scs))
|
||||||
|
goto err_truncate;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
err_truncate:
|
||||||
|
my_error(ER_EVENT_DATA_TOO_LONG, MYF(0), table->field[field_num]->field_name);
|
||||||
|
DBUG_RETURN(EVEX_GENERAL_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Find row in open mysql.event table representing event
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
evex_db_find_event_by_name()
|
||||||
|
thd Thread context
|
||||||
|
dbname Name of event's database
|
||||||
|
rname Name of the event inside the db
|
||||||
|
table TABLE object for open mysql.event table.
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
0 - Routine found
|
||||||
|
EVEX_KEY_NOT_FOUND - No routine with given name
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
|
||||||
|
const LEX_STRING ev_name,
|
||||||
|
TABLE *table)
|
||||||
|
{
|
||||||
|
return Events::get_instance()->db_repository.
|
||||||
|
find_event_by_name(thd, dbname, ev_name, table);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Looks for a named event in mysql.event and in case of success returns
|
||||||
|
an object will data loaded from the table.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
db_find_event()
|
||||||
|
thd THD
|
||||||
|
name the name of the event to find
|
||||||
|
ett event's data if event is found
|
||||||
|
tbl TABLE object to use when not NULL
|
||||||
|
|
||||||
|
NOTES
|
||||||
|
1) Use sp_name for look up, return in **ett if found
|
||||||
|
2) tbl is not closed at exit
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
0 ok In this case *ett is set to the event
|
||||||
|
# error *ett == 0
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
Event_db_repository::find_event(THD *thd, sp_name *name, Event_timed **ett,
|
||||||
|
TABLE *tbl, MEM_ROOT *root)
|
||||||
|
{
|
||||||
|
TABLE *table;
|
||||||
|
int ret;
|
||||||
|
Event_timed *et= NULL;
|
||||||
|
DBUG_ENTER("db_find_event");
|
||||||
|
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
|
||||||
|
|
||||||
|
if (tbl)
|
||||||
|
table= tbl;
|
||||||
|
else if (Events::get_instance()->db_repository.open_event_table(thd, TL_READ, &table))
|
||||||
|
{
|
||||||
|
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
||||||
|
ret= EVEX_GENERAL_ERROR;
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret= evex_db_find_event_by_name(thd, name->m_db, name->m_name, table)))
|
||||||
|
{
|
||||||
|
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name->m_name.str);
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
et= new Event_timed;
|
||||||
|
|
||||||
|
/*
|
||||||
|
1)The table should not be closed beforehand. ::load_from_row() only loads
|
||||||
|
and does not compile
|
||||||
|
|
||||||
|
2)::load_from_row() is silent on error therefore we emit error msg here
|
||||||
|
*/
|
||||||
|
if ((ret= et->load_from_row(root, table)))
|
||||||
|
{
|
||||||
|
my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
if (ret)
|
||||||
|
{
|
||||||
|
delete et;
|
||||||
|
et= 0;
|
||||||
|
}
|
||||||
|
/* don't close the table if we haven't opened it ourselves */
|
||||||
|
if (!tbl && table)
|
||||||
|
close_thread_tables(thd);
|
||||||
|
*ett= et;
|
||||||
|
DBUG_RETURN(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
Event_db_repository::init_repository()
|
||||||
|
{
|
||||||
|
init_alloc_root(&repo_root, MEM_ROOT_BLOCK_SIZE, MEM_ROOT_PREALLOC);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
Event_db_repository::deinit_repository()
|
||||||
|
{
|
||||||
|
free_root(&repo_root, MYF(0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Open mysql.event table for read
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
Events::open_event_table()
|
||||||
|
thd Thread context
|
||||||
|
lock_type How to lock the table
|
||||||
|
table We will store the open table here
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
1 Cannot lock table
|
||||||
|
2 The table is corrupted - different number of fields
|
||||||
|
0 OK
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
Event_db_repository::open_event_table(THD *thd, enum thr_lock_type lock_type,
|
||||||
|
TABLE **table)
|
||||||
|
{
|
||||||
|
TABLE_LIST tables;
|
||||||
|
DBUG_ENTER("Event_db_repository::open_event_table");
|
||||||
|
|
||||||
|
bzero((char*) &tables, sizeof(tables));
|
||||||
|
tables.db= (char*) "mysql";
|
||||||
|
tables.table_name= tables.alias= (char*) "event";
|
||||||
|
tables.lock_type= lock_type;
|
||||||
|
|
||||||
|
if (simple_open_n_lock_tables(thd, &tables))
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
|
||||||
|
if (table_check_intact(tables.table, ET_FIELD_COUNT,
|
||||||
|
event_table_fields,
|
||||||
|
&mysql_event_last_create_time,
|
||||||
|
ER_CANNOT_LOAD_FROM_TABLE))
|
||||||
|
{
|
||||||
|
close_thread_tables(thd);
|
||||||
|
DBUG_RETURN(2);
|
||||||
|
}
|
||||||
|
*table= tables.table;
|
||||||
|
tables.table->use_all_columns();
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Creates an event in mysql.event
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
Event_db_repository::create_event()
|
||||||
|
thd THD
|
||||||
|
et Event_timed object containing information for the event
|
||||||
|
create_if_not If an warning should be generated in case event exists
|
||||||
|
rows_affected How many rows were affected
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
0 - OK
|
||||||
|
EVEX_GENERAL_ERROR - Failure
|
||||||
|
|
||||||
|
DESCRIPTION
|
||||||
|
Creates an event. Relies on evex_fill_row which is shared with
|
||||||
|
db_update_event. The name of the event is inside "et".
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
Event_db_repository::create_event(THD *thd, Event_timed *et,
|
||||||
|
my_bool create_if_not, uint *rows_affected)
|
||||||
|
{
|
||||||
|
int ret= 0;
|
||||||
|
CHARSET_INFO *scs= system_charset_info;
|
||||||
|
TABLE *table;
|
||||||
|
char olddb[128];
|
||||||
|
bool dbchanged= false;
|
||||||
|
DBUG_ENTER("Event_db_repository::create_event");
|
||||||
|
DBUG_PRINT("enter", ("name: %.*s", et->name.length, et->name.str));
|
||||||
|
|
||||||
|
*rows_affected= 0;
|
||||||
|
DBUG_PRINT("info", ("open mysql.event for update"));
|
||||||
|
if (open_event_table(thd, TL_WRITE, &table))
|
||||||
|
{
|
||||||
|
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBUG_PRINT("info", ("check existance of an event with the same name"));
|
||||||
|
if (!evex_db_find_event_by_name(thd, et->dbname, et->name, table))
|
||||||
|
{
|
||||||
|
if (create_if_not)
|
||||||
|
{
|
||||||
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||||
|
ER_EVENT_ALREADY_EXISTS, ER(ER_EVENT_ALREADY_EXISTS),
|
||||||
|
et->name.str);
|
||||||
|
goto ok;
|
||||||
|
}
|
||||||
|
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), et->name.str);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
DBUG_PRINT("info", ("non-existant, go forward"));
|
||||||
|
if ((ret= sp_use_new_db(thd, et->dbname.str,olddb, sizeof(olddb),0,
|
||||||
|
&dbchanged)))
|
||||||
|
{
|
||||||
|
my_error(ER_BAD_DB_ERROR, MYF(0));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
restore_record(table, s->default_values); // Get default values for fields
|
||||||
|
|
||||||
|
if (system_charset_info->cset->numchars(system_charset_info, et->dbname.str,
|
||||||
|
et->dbname.str + et->dbname.length)
|
||||||
|
> EVEX_DB_FIELD_LEN)
|
||||||
|
{
|
||||||
|
my_error(ER_TOO_LONG_IDENT, MYF(0), et->dbname.str);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
if (system_charset_info->cset->numchars(system_charset_info, et->name.str,
|
||||||
|
et->name.str + et->name.length)
|
||||||
|
> EVEX_DB_FIELD_LEN)
|
||||||
|
{
|
||||||
|
my_error(ER_TOO_LONG_IDENT, MYF(0), et->name.str);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (et->body.length > table->field[ET_FIELD_BODY]->field_length)
|
||||||
|
{
|
||||||
|
my_error(ER_TOO_LONG_BODY, MYF(0), et->name.str);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(et->expression) && !(et->execute_at.year))
|
||||||
|
{
|
||||||
|
DBUG_PRINT("error", ("neither expression nor execute_at are set!"));
|
||||||
|
my_error(ER_EVENT_NEITHER_M_EXPR_NOR_M_AT, MYF(0));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
((Field_timestamp *)table->field[ET_FIELD_CREATED])->set_time();
|
||||||
|
|
||||||
|
/*
|
||||||
|
evex_fill_row() calls my_error() in case of error so no need to
|
||||||
|
handle it here
|
||||||
|
*/
|
||||||
|
if ((ret= evex_fill_row(thd, table, et, false)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (table->file->ha_write_row(table->record[0]))
|
||||||
|
{
|
||||||
|
my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef USE_THIS_CODE_AS_TEMPLATE_WHEN_EVENT_REPLICATION_IS_AGREED
|
||||||
|
if (mysql_bin_log.is_open())
|
||||||
|
{
|
||||||
|
thd->clear_error();
|
||||||
|
/* Such a statement can always go directly to binlog, no trans cache */
|
||||||
|
thd->binlog_query(THD::MYSQL_QUERY_TYPE, thd->query, thd->query_length,
|
||||||
|
FALSE, FALSE);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
*rows_affected= 1;
|
||||||
|
ok:
|
||||||
|
if (dbchanged)
|
||||||
|
(void) mysql_change_db(thd, olddb, 1);
|
||||||
|
if (table)
|
||||||
|
close_thread_tables(thd);
|
||||||
|
DBUG_RETURN(EVEX_OK);
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (dbchanged)
|
||||||
|
(void) mysql_change_db(thd, olddb, 1);
|
||||||
|
if (table)
|
||||||
|
close_thread_tables(thd);
|
||||||
|
DBUG_RETURN(EVEX_GENERAL_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Used to execute ALTER EVENT. Pendant to Events::update_event().
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
Event_db_repository::update_event()
|
||||||
|
thd THD
|
||||||
|
sp_name the name of the event to alter
|
||||||
|
et event's data
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
0 OK
|
||||||
|
EVEX_GENERAL_ERROR Error occured (my_error() called)
|
||||||
|
|
||||||
|
NOTES
|
||||||
|
sp_name is passed since this is the name of the event to
|
||||||
|
alter in case of RENAME TO.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
Event_db_repository::update_event(THD *thd, Event_timed *et, sp_name *new_name)
|
||||||
|
{
|
||||||
|
CHARSET_INFO *scs= system_charset_info;
|
||||||
|
TABLE *table;
|
||||||
|
int ret= EVEX_OPEN_TABLE_FAILED;
|
||||||
|
DBUG_ENTER("Event_db_repository::update_event");
|
||||||
|
DBUG_PRINT("enter", ("dbname: %.*s", et->dbname.length, et->dbname.str));
|
||||||
|
DBUG_PRINT("enter", ("name: %.*s", et->name.length, et->name.str));
|
||||||
|
DBUG_PRINT("enter", ("user: %.*s", et->definer.length, et->definer.str));
|
||||||
|
if (new_name)
|
||||||
|
DBUG_PRINT("enter", ("rename to: %.*s", new_name->m_name.length,
|
||||||
|
new_name->m_name.str));
|
||||||
|
|
||||||
|
if (open_event_table(thd, TL_WRITE, &table))
|
||||||
|
{
|
||||||
|
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* first look whether we overwrite */
|
||||||
|
if (new_name)
|
||||||
|
{
|
||||||
|
if (!sortcmp_lex_string(et->name, new_name->m_name, scs) &&
|
||||||
|
!sortcmp_lex_string(et->dbname, new_name->m_db, scs))
|
||||||
|
{
|
||||||
|
my_error(ER_EVENT_SAME_NAME, MYF(0), et->name.str);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!evex_db_find_event_by_name(thd,new_name->m_db,new_name->m_name,table))
|
||||||
|
{
|
||||||
|
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->m_name.str);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
...and then if there is such an event. Don't exchange the blocks
|
||||||
|
because you will get error 120 from table handler because new_name will
|
||||||
|
overwrite the key and SE will tell us that it cannot find the already found
|
||||||
|
row (copied into record[1] later
|
||||||
|
*/
|
||||||
|
if (EVEX_KEY_NOT_FOUND == find_event_by_name(thd, et->dbname, et->name, table))
|
||||||
|
{
|
||||||
|
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), et->name.str);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
store_record(table,record[1]);
|
||||||
|
|
||||||
|
/* Don't update create on row update. */
|
||||||
|
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
|
||||||
|
|
||||||
|
/*
|
||||||
|
evex_fill_row() calls my_error() in case of error so no need to
|
||||||
|
handle it here
|
||||||
|
*/
|
||||||
|
if ((ret= evex_fill_row(thd, table, et, true)))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
if (new_name)
|
||||||
|
{
|
||||||
|
table->field[ET_FIELD_DB]->
|
||||||
|
store(new_name->m_db.str, new_name->m_db.length, scs);
|
||||||
|
table->field[ET_FIELD_NAME]->
|
||||||
|
store(new_name->m_name.str, new_name->m_name.length, scs);
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((ret= table->file->ha_update_row(table->record[1], table->record[0])))
|
||||||
|
{
|
||||||
|
my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* close mysql.event or we crash later when loading the event from disk */
|
||||||
|
close_thread_tables(thd);
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
|
err:
|
||||||
|
if (table)
|
||||||
|
close_thread_tables(thd);
|
||||||
|
DBUG_RETURN(EVEX_GENERAL_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Drops an event
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
Event_db_repository::drop_event()
|
||||||
|
thd THD
|
||||||
|
db database name
|
||||||
|
name event's name
|
||||||
|
drop_if_exists if set and the event not existing => warning onto the stack
|
||||||
|
rows_affected affected number of rows is returned heres
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
0 OK
|
||||||
|
!0 Error (my_error() called)
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
Event_db_repository::drop_event(THD *thd, LEX_STRING db, LEX_STRING name,
|
||||||
|
bool drop_if_exists, uint *rows_affected)
|
||||||
|
{
|
||||||
|
TABLE *table;
|
||||||
|
Open_tables_state backup;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
DBUG_ENTER("Event_db_repository::drop_event");
|
||||||
|
DBUG_PRINT("enter", ("db=%s name=%s", db.str, name.str));
|
||||||
|
ret= EVEX_OPEN_TABLE_FAILED;
|
||||||
|
|
||||||
|
thd->reset_n_backup_open_tables_state(&backup);
|
||||||
|
if (open_event_table(thd, TL_WRITE, &table))
|
||||||
|
{
|
||||||
|
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!(ret= evex_db_find_event_by_name(thd, db, name, table)))
|
||||||
|
{
|
||||||
|
if ((ret= table->file->ha_delete_row(table->record[0])))
|
||||||
|
my_error(ER_EVENT_CANNOT_DELETE, MYF(0));
|
||||||
|
}
|
||||||
|
else if (ret == EVEX_KEY_NOT_FOUND)
|
||||||
|
{
|
||||||
|
if (drop_if_exists)
|
||||||
|
{
|
||||||
|
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
||||||
|
ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
|
||||||
|
"Event", name.str);
|
||||||
|
ret= 0;
|
||||||
|
} else
|
||||||
|
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
|
||||||
|
}
|
||||||
|
|
||||||
|
done:
|
||||||
|
/*
|
||||||
|
evex_drop_event() is used by Event_timed::drop therefore
|
||||||
|
we have to close our thread tables.
|
||||||
|
*/
|
||||||
|
close_thread_tables(thd);
|
||||||
|
thd->restore_backup_open_tables_state(&backup);
|
||||||
|
DBUG_RETURN(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
Event_db_repository::find_event_by_name(THD *thd, LEX_STRING db,
|
||||||
|
LEX_STRING name, TABLE *table)
|
||||||
|
{
|
||||||
|
byte key[MAX_KEY_LENGTH];
|
||||||
|
DBUG_ENTER("Event_db_repository::find_event_by_name");
|
||||||
|
DBUG_PRINT("enter", ("name: %.*s", name.length, name.str));
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create key to find row. We have to use field->store() to be able to
|
||||||
|
handle VARCHAR and CHAR fields.
|
||||||
|
Assumption here is that the two first fields in the table are
|
||||||
|
'db' and 'name' and the first key is the primary key over the
|
||||||
|
same fields.
|
||||||
|
*/
|
||||||
|
if (db.length > table->field[ET_FIELD_DB]->field_length ||
|
||||||
|
name.length > table->field[ET_FIELD_NAME]->field_length)
|
||||||
|
|
||||||
|
DBUG_RETURN(EVEX_KEY_NOT_FOUND);
|
||||||
|
|
||||||
|
table->field[ET_FIELD_DB]->store(db.str, db.length, &my_charset_bin);
|
||||||
|
table->field[ET_FIELD_NAME]->store(name.str, name.length, &my_charset_bin);
|
||||||
|
|
||||||
|
key_copy(key, table->record[0], table->key_info,
|
||||||
|
table->key_info->key_length);
|
||||||
|
|
||||||
|
if (table->file->index_read_idx(table->record[0], 0, key,
|
||||||
|
table->key_info->key_length,
|
||||||
|
HA_READ_KEY_EXACT))
|
||||||
|
{
|
||||||
|
DBUG_PRINT("info", ("Row not found"));
|
||||||
|
DBUG_RETURN(EVEX_KEY_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
DBUG_PRINT("info", ("Row found!"));
|
||||||
|
DBUG_RETURN(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
Event_db_repository::drop_schema_events(THD *thd, LEX_STRING schema)
|
||||||
|
{
|
||||||
|
return drop_events_by_field(thd, ET_FIELD_DB, schema);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
Event_db_repository::drop_user_events(THD *thd, LEX_STRING definer)
|
||||||
|
{
|
||||||
|
return drop_events_by_field(thd, ET_FIELD_DEFINER, definer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Drops all events in the selected database, from mysql.event.
|
||||||
|
|
||||||
|
SYNOPSIS
|
||||||
|
drop_events_from_table_by_field()
|
||||||
|
thd Thread
|
||||||
|
table mysql.event TABLE
|
||||||
|
field Which field of the row to use for matching
|
||||||
|
field_value The value that should match
|
||||||
|
|
||||||
|
RETURN VALUE
|
||||||
|
0 OK
|
||||||
|
!0 Error from ha_delete_row
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
Event_db_repository::drop_events_by_field(THD *thd,
|
||||||
|
enum enum_events_table_field field,
|
||||||
|
LEX_STRING field_value)
|
||||||
|
{
|
||||||
|
int ret= 0;
|
||||||
|
TABLE *table;
|
||||||
|
Open_tables_state backup;
|
||||||
|
READ_RECORD read_record_info;
|
||||||
|
DBUG_ENTER("drop_events_from_table_by_field");
|
||||||
|
DBUG_PRINT("enter", ("field=%d field_value=%s", field, field_value.str));
|
||||||
|
|
||||||
|
if (open_event_table(thd, TL_WRITE, &table))
|
||||||
|
{
|
||||||
|
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
||||||
|
DBUG_RETURN(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* only enabled events are in memory, so we go now and delete the rest */
|
||||||
|
init_read_record(&read_record_info, thd, table, NULL, 1, 0);
|
||||||
|
while (!ret && !(read_record_info.read_record(&read_record_info)) )
|
||||||
|
{
|
||||||
|
char *et_field= get_field(thd->mem_root, table->field[field]);
|
||||||
|
|
||||||
|
LEX_STRING et_field_lex= {et_field, strlen(et_field)};
|
||||||
|
DBUG_PRINT("info", ("Current event %s name=%s", et_field,
|
||||||
|
get_field(thd->mem_root, table->field[ET_FIELD_NAME])));
|
||||||
|
|
||||||
|
if (!sortcmp_lex_string(et_field_lex, field_value, system_charset_info))
|
||||||
|
{
|
||||||
|
DBUG_PRINT("info", ("Dropping"));
|
||||||
|
if ((ret= table->file->ha_delete_row(table->record[0])))
|
||||||
|
my_error(ER_EVENT_DROP_FAILED, MYF(0),
|
||||||
|
get_field(thd->mem_root, table->field[ET_FIELD_NAME]));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end_read_record(&read_record_info);
|
||||||
|
thd->version--; /* Force close to free memory */
|
||||||
|
|
||||||
|
DBUG_RETURN(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
Event_db_repository::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= find_event(thd, &spn, &et_loaded, NULL, &repo_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);
|
||||||
|
}
|
||||||
|
@ -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 @@
|
|||||||
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)
|
|||||||
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"));
|
||||||
@ -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,
|
|||||||
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,
|
|||||||
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)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
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,
|
|||||||
{
|
{
|
||||||
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,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
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)
|
|||||||
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)
|
|||||||
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()
|
|||||||
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()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
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)
|
|||||||
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 @@
|
|||||||
|
|
||||||
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();
|
|||||||
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 @@ 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);
|
||||||
|
|
||||||
@ -78,10 +68,10 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
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 @@ 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();
|
||||||
@ -156,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
|
||||||
@ -230,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;
|
||||||
|
|
||||||
|
806
sql/events.cc
806
sql/events.cc
@ -15,11 +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 "sp.h"
|
#include "event_db_repository.h"
|
||||||
#include "sp_head.h"
|
#include "sp_head.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -48,10 +47,6 @@ Warning:
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
MEM_ROOT evex_mem_root;
|
|
||||||
time_t mysql_event_last_create_time= 0L;
|
|
||||||
|
|
||||||
|
|
||||||
const char *event_scheduler_state_names[]=
|
const char *event_scheduler_state_names[]=
|
||||||
{ "OFF", "0", "ON", "1", "SUSPEND", "2", NullS };
|
{ "OFF", "0", "ON", "1", "SUSPEND", "2", NullS };
|
||||||
|
|
||||||
@ -63,104 +58,10 @@ TYPELIB Events::opt_typelib=
|
|||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Events Events::singleton;
|
||||||
|
|
||||||
ulong Events::opt_event_scheduler= 2;
|
ulong Events::opt_event_scheduler= 2;
|
||||||
|
|
||||||
static
|
|
||||||
TABLE_FIELD_W_TYPE event_table_fields[Events::FIELD_COUNT] = {
|
|
||||||
{
|
|
||||||
{(char *) STRING_WITH_LEN("db")},
|
|
||||||
{(char *) STRING_WITH_LEN("char(64)")},
|
|
||||||
{(char *) STRING_WITH_LEN("utf8")}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{(char *) STRING_WITH_LEN("name")},
|
|
||||||
{(char *) STRING_WITH_LEN("char(64)")},
|
|
||||||
{(char *) STRING_WITH_LEN("utf8")}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{(char *) STRING_WITH_LEN("body")},
|
|
||||||
{(char *) STRING_WITH_LEN("longblob")},
|
|
||||||
{NULL, 0}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{(char *) STRING_WITH_LEN("definer")},
|
|
||||||
{(char *) STRING_WITH_LEN("char(77)")},
|
|
||||||
{(char *) STRING_WITH_LEN("utf8")}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{(char *) STRING_WITH_LEN("execute_at")},
|
|
||||||
{(char *) STRING_WITH_LEN("datetime")},
|
|
||||||
{NULL, 0}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{(char *) STRING_WITH_LEN("interval_value")},
|
|
||||||
{(char *) STRING_WITH_LEN("int(11)")},
|
|
||||||
{NULL, 0}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{(char *) STRING_WITH_LEN("interval_field")},
|
|
||||||
{(char *) STRING_WITH_LEN("enum('YEAR','QUARTER','MONTH','DAY',"
|
|
||||||
"'HOUR','MINUTE','WEEK','SECOND','MICROSECOND','YEAR_MONTH','DAY_HOUR',"
|
|
||||||
"'DAY_MINUTE','DAY_SECOND','HOUR_MINUTE','HOUR_SECOND','MINUTE_SECOND',"
|
|
||||||
"'DAY_MICROSECOND','HOUR_MICROSECOND','MINUTE_MICROSECOND',"
|
|
||||||
"'SECOND_MICROSECOND')")},
|
|
||||||
{NULL, 0}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{(char *) STRING_WITH_LEN("created")},
|
|
||||||
{(char *) STRING_WITH_LEN("timestamp")},
|
|
||||||
{NULL, 0}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{(char *) STRING_WITH_LEN("modified")},
|
|
||||||
{(char *) STRING_WITH_LEN("timestamp")},
|
|
||||||
{NULL, 0}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{(char *) STRING_WITH_LEN("last_executed")},
|
|
||||||
{(char *) STRING_WITH_LEN("datetime")},
|
|
||||||
{NULL, 0}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{(char *) STRING_WITH_LEN("starts")},
|
|
||||||
{(char *) STRING_WITH_LEN("datetime")},
|
|
||||||
{NULL, 0}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{(char *) STRING_WITH_LEN("ends")},
|
|
||||||
{(char *) STRING_WITH_LEN("datetime")},
|
|
||||||
{NULL, 0}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{(char *) STRING_WITH_LEN("status")},
|
|
||||||
{(char *) STRING_WITH_LEN("enum('ENABLED','DISABLED')")},
|
|
||||||
{NULL, 0}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{(char *) STRING_WITH_LEN("on_completion")},
|
|
||||||
{(char *) STRING_WITH_LEN("enum('DROP','PRESERVE')")},
|
|
||||||
{NULL, 0}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{(char *) STRING_WITH_LEN("sql_mode")},
|
|
||||||
{(char *) STRING_WITH_LEN("set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES',"
|
|
||||||
"'IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION',"
|
|
||||||
"'NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB',"
|
|
||||||
"'NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40',"
|
|
||||||
"'ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES',"
|
|
||||||
"'STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES',"
|
|
||||||
"'ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER',"
|
|
||||||
"'HIGH_NOT_PRECEDENCE')")},
|
|
||||||
{NULL, 0}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
{(char *) STRING_WITH_LEN("comment")},
|
|
||||||
{(char *) STRING_WITH_LEN("char(64)")},
|
|
||||||
{(char *) STRING_WITH_LEN("utf8")}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Compares 2 LEX strings regarding case.
|
Compares 2 LEX strings regarding case.
|
||||||
@ -188,6 +89,14 @@ int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Events *
|
||||||
|
Events::get_instance()
|
||||||
|
{
|
||||||
|
DBUG_ENTER("Events::get_instance");
|
||||||
|
DBUG_RETURN(&singleton);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Reconstructs interval expression from interval type and expression
|
Reconstructs interval expression from interval type and expression
|
||||||
value that is in form of a value of the smalles entity:
|
value that is in form of a value of the smalles entity:
|
||||||
@ -207,8 +116,7 @@ int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
int
|
int
|
||||||
Events::reconstruct_interval_expression(String *buf,
|
Events::reconstruct_interval_expression(String *buf, interval_type interval,
|
||||||
interval_type interval,
|
|
||||||
longlong expression)
|
longlong expression)
|
||||||
{
|
{
|
||||||
ulonglong expr= expression;
|
ulonglong expr= expression;
|
||||||
@ -341,545 +249,7 @@ int
|
|||||||
Events::open_event_table(THD *thd, enum thr_lock_type lock_type,
|
Events::open_event_table(THD *thd, enum thr_lock_type lock_type,
|
||||||
TABLE **table)
|
TABLE **table)
|
||||||
{
|
{
|
||||||
TABLE_LIST tables;
|
return db_repository.open_event_table(thd, lock_type, table);
|
||||||
DBUG_ENTER("open_events_table");
|
|
||||||
|
|
||||||
bzero((char*) &tables, sizeof(tables));
|
|
||||||
tables.db= (char*) "mysql";
|
|
||||||
tables.table_name= tables.alias= (char*) "event";
|
|
||||||
tables.lock_type= lock_type;
|
|
||||||
|
|
||||||
if (simple_open_n_lock_tables(thd, &tables))
|
|
||||||
DBUG_RETURN(1);
|
|
||||||
|
|
||||||
if (table_check_intact(tables.table, Events::FIELD_COUNT,
|
|
||||||
event_table_fields,
|
|
||||||
&mysql_event_last_create_time,
|
|
||||||
ER_CANNOT_LOAD_FROM_TABLE))
|
|
||||||
{
|
|
||||||
close_thread_tables(thd);
|
|
||||||
DBUG_RETURN(2);
|
|
||||||
}
|
|
||||||
*table= tables.table;
|
|
||||||
tables.table->use_all_columns();
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Find row in open mysql.event table representing event
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
evex_db_find_event_aux()
|
|
||||||
thd Thread context
|
|
||||||
et event_timed object containing dbname & name
|
|
||||||
table TABLE object for open mysql.event table.
|
|
||||||
|
|
||||||
RETURN VALUE
|
|
||||||
0 - Routine found
|
|
||||||
EVEX_KEY_NOT_FOUND - No routine with given name
|
|
||||||
*/
|
|
||||||
|
|
||||||
inline int
|
|
||||||
evex_db_find_event_aux(THD *thd, Event_timed *et, TABLE *table)
|
|
||||||
{
|
|
||||||
return evex_db_find_event_by_name(thd, et->dbname, et->name, table);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Find row in open mysql.event table representing event
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
evex_db_find_event_by_name()
|
|
||||||
thd Thread context
|
|
||||||
dbname Name of event's database
|
|
||||||
rname Name of the event inside the db
|
|
||||||
table TABLE object for open mysql.event table.
|
|
||||||
|
|
||||||
RETURN VALUE
|
|
||||||
0 - Routine found
|
|
||||||
EVEX_KEY_NOT_FOUND - No routine with given name
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname,
|
|
||||||
const LEX_STRING ev_name,
|
|
||||||
TABLE *table)
|
|
||||||
{
|
|
||||||
byte key[MAX_KEY_LENGTH];
|
|
||||||
DBUG_ENTER("evex_db_find_event_by_name");
|
|
||||||
DBUG_PRINT("enter", ("name: %.*s", ev_name.length, ev_name.str));
|
|
||||||
|
|
||||||
/*
|
|
||||||
Create key to find row. We have to use field->store() to be able to
|
|
||||||
handle VARCHAR and CHAR fields.
|
|
||||||
Assumption here is that the two first fields in the table are
|
|
||||||
'db' and 'name' and the first key is the primary key over the
|
|
||||||
same fields.
|
|
||||||
*/
|
|
||||||
if (dbname.length > table->field[Events::FIELD_DB]->field_length ||
|
|
||||||
ev_name.length > table->field[Events::FIELD_NAME]->field_length)
|
|
||||||
|
|
||||||
DBUG_RETURN(EVEX_KEY_NOT_FOUND);
|
|
||||||
|
|
||||||
table->field[Events::FIELD_DB]->store(dbname.str, dbname.length,
|
|
||||||
&my_charset_bin);
|
|
||||||
table->field[Events::FIELD_NAME]->store(ev_name.str, ev_name.length,
|
|
||||||
&my_charset_bin);
|
|
||||||
|
|
||||||
key_copy(key, table->record[0], table->key_info,
|
|
||||||
table->key_info->key_length);
|
|
||||||
|
|
||||||
if (table->file->index_read_idx(table->record[0], 0, key,
|
|
||||||
table->key_info->key_length,
|
|
||||||
HA_READ_KEY_EXACT))
|
|
||||||
{
|
|
||||||
DBUG_PRINT("info", ("Row not found"));
|
|
||||||
DBUG_RETURN(EVEX_KEY_NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
DBUG_PRINT("info", ("Row found!"));
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Puts some data common to CREATE and ALTER EVENT into a row.
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
evex_fill_row()
|
|
||||||
thd THD
|
|
||||||
table the row to fill out
|
|
||||||
et Event's data
|
|
||||||
|
|
||||||
RETURN VALUE
|
|
||||||
0 - OK
|
|
||||||
EVEX_GENERAL_ERROR - bad data
|
|
||||||
EVEX_GET_FIELD_FAILED - field count does not match. table corrupted?
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Used both when an event is created and when it is altered.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int
|
|
||||||
evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update)
|
|
||||||
{
|
|
||||||
CHARSET_INFO *scs= system_charset_info;
|
|
||||||
enum Events::enum_table_field field_num;
|
|
||||||
|
|
||||||
DBUG_ENTER("evex_fill_row");
|
|
||||||
|
|
||||||
DBUG_PRINT("info", ("dbname=[%s]", et->dbname.str));
|
|
||||||
DBUG_PRINT("info", ("name =[%s]", et->name.str));
|
|
||||||
DBUG_PRINT("info", ("body =[%s]", et->body.str));
|
|
||||||
|
|
||||||
if (table->field[field_num= Events::FIELD_DEFINER]->
|
|
||||||
store(et->definer.str, et->definer.length, scs))
|
|
||||||
goto err_truncate;
|
|
||||||
|
|
||||||
if (table->field[field_num= Events::FIELD_DB]->
|
|
||||||
store(et->dbname.str, et->dbname.length, scs))
|
|
||||||
goto err_truncate;
|
|
||||||
|
|
||||||
if (table->field[field_num= Events::FIELD_NAME]->
|
|
||||||
store(et->name.str, et->name.length, scs))
|
|
||||||
goto err_truncate;
|
|
||||||
|
|
||||||
/* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()*/
|
|
||||||
table->field[Events::FIELD_ON_COMPLETION]->
|
|
||||||
store((longlong)et->on_completion, true);
|
|
||||||
|
|
||||||
table->field[Events::FIELD_STATUS]->store((longlong)et->status, true);
|
|
||||||
|
|
||||||
/*
|
|
||||||
Change the SQL_MODE only if body was present in an ALTER EVENT and of course
|
|
||||||
always during CREATE EVENT.
|
|
||||||
*/
|
|
||||||
if (et->body.str)
|
|
||||||
{
|
|
||||||
table->field[Events::FIELD_SQL_MODE]->
|
|
||||||
store((longlong)thd->variables.sql_mode, true);
|
|
||||||
|
|
||||||
if (table->field[field_num= Events::FIELD_BODY]->
|
|
||||||
store(et->body.str, et->body.length, scs))
|
|
||||||
goto err_truncate;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (et->expression)
|
|
||||||
{
|
|
||||||
table->field[Events::FIELD_INTERVAL_EXPR]->set_notnull();
|
|
||||||
table->field[Events::FIELD_INTERVAL_EXPR]->
|
|
||||||
store((longlong)et->expression, true);
|
|
||||||
|
|
||||||
table->field[Events::FIELD_TRANSIENT_INTERVAL]->set_notnull();
|
|
||||||
/*
|
|
||||||
In the enum (C) intervals start from 0 but in mysql enum valid values start
|
|
||||||
from 1. Thus +1 offset is needed!
|
|
||||||
*/
|
|
||||||
table->field[Events::FIELD_TRANSIENT_INTERVAL]->
|
|
||||||
store((longlong)et->interval+1, true);
|
|
||||||
|
|
||||||
table->field[Events::FIELD_EXECUTE_AT]->set_null();
|
|
||||||
|
|
||||||
if (!et->starts_null)
|
|
||||||
{
|
|
||||||
table->field[Events::FIELD_STARTS]->set_notnull();
|
|
||||||
table->field[Events::FIELD_STARTS]->
|
|
||||||
store_time(&et->starts, MYSQL_TIMESTAMP_DATETIME);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!et->ends_null)
|
|
||||||
{
|
|
||||||
table->field[Events::FIELD_ENDS]->set_notnull();
|
|
||||||
table->field[Events::FIELD_ENDS]->
|
|
||||||
store_time(&et->ends, MYSQL_TIMESTAMP_DATETIME);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (et->execute_at.year)
|
|
||||||
{
|
|
||||||
table->field[Events::FIELD_INTERVAL_EXPR]->set_null();
|
|
||||||
table->field[Events::FIELD_TRANSIENT_INTERVAL]->set_null();
|
|
||||||
table->field[Events::FIELD_STARTS]->set_null();
|
|
||||||
table->field[Events::FIELD_ENDS]->set_null();
|
|
||||||
|
|
||||||
table->field[Events::FIELD_EXECUTE_AT]->set_notnull();
|
|
||||||
table->field[Events::FIELD_EXECUTE_AT]->
|
|
||||||
store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
DBUG_ASSERT(is_update);
|
|
||||||
/*
|
|
||||||
it is normal to be here when the action is update
|
|
||||||
this is an error if the action is create. something is borked
|
|
||||||
*/
|
|
||||||
}
|
|
||||||
|
|
||||||
((Field_timestamp *)table->field[Events::FIELD_MODIFIED])->set_time();
|
|
||||||
|
|
||||||
if (et->comment.str)
|
|
||||||
{
|
|
||||||
if (table->field[field_num= Events::FIELD_COMMENT]->
|
|
||||||
store(et->comment.str, et->comment.length, scs))
|
|
||||||
goto err_truncate;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
err_truncate:
|
|
||||||
my_error(ER_EVENT_DATA_TOO_LONG, MYF(0), table->field[field_num]->field_name);
|
|
||||||
DBUG_RETURN(EVEX_GENERAL_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Creates an event in mysql.event
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
db_create_event()
|
|
||||||
thd THD
|
|
||||||
et Event_timed object containing information for the event
|
|
||||||
create_if_not If an warning should be generated in case event exists
|
|
||||||
rows_affected How many rows were affected
|
|
||||||
|
|
||||||
RETURN VALUE
|
|
||||||
0 - OK
|
|
||||||
EVEX_GENERAL_ERROR - Failure
|
|
||||||
|
|
||||||
DESCRIPTION
|
|
||||||
Creates an event. Relies on evex_fill_row which is shared with
|
|
||||||
db_update_event. The name of the event is inside "et".
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
db_create_event(THD *thd, Event_timed *et, my_bool create_if_not,
|
|
||||||
uint *rows_affected)
|
|
||||||
{
|
|
||||||
int ret= 0;
|
|
||||||
CHARSET_INFO *scs= system_charset_info;
|
|
||||||
TABLE *table;
|
|
||||||
char olddb[128];
|
|
||||||
bool dbchanged= false;
|
|
||||||
DBUG_ENTER("db_create_event");
|
|
||||||
DBUG_PRINT("enter", ("name: %.*s", et->name.length, et->name.str));
|
|
||||||
|
|
||||||
*rows_affected= 0;
|
|
||||||
DBUG_PRINT("info", ("open mysql.event for update"));
|
|
||||||
if (Events::open_event_table(thd, TL_WRITE, &table))
|
|
||||||
{
|
|
||||||
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBUG_PRINT("info", ("check existance of an event with the same name"));
|
|
||||||
if (!evex_db_find_event_aux(thd, et, table))
|
|
||||||
{
|
|
||||||
if (create_if_not)
|
|
||||||
{
|
|
||||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
|
||||||
ER_EVENT_ALREADY_EXISTS, ER(ER_EVENT_ALREADY_EXISTS),
|
|
||||||
et->name.str);
|
|
||||||
goto ok;
|
|
||||||
}
|
|
||||||
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), et->name.str);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
DBUG_PRINT("info", ("non-existant, go forward"));
|
|
||||||
if ((ret= sp_use_new_db(thd, et->dbname.str,olddb, sizeof(olddb),0,
|
|
||||||
&dbchanged)))
|
|
||||||
{
|
|
||||||
my_error(ER_BAD_DB_ERROR, MYF(0));
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
restore_record(table, s->default_values); // Get default values for fields
|
|
||||||
|
|
||||||
if (system_charset_info->cset->numchars(system_charset_info, et->dbname.str,
|
|
||||||
et->dbname.str + et->dbname.length)
|
|
||||||
> EVEX_DB_FIELD_LEN)
|
|
||||||
{
|
|
||||||
my_error(ER_TOO_LONG_IDENT, MYF(0), et->dbname.str);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
if (system_charset_info->cset->numchars(system_charset_info, et->name.str,
|
|
||||||
et->name.str + et->name.length)
|
|
||||||
> EVEX_DB_FIELD_LEN)
|
|
||||||
{
|
|
||||||
my_error(ER_TOO_LONG_IDENT, MYF(0), et->name.str);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (et->body.length > table->field[Events::FIELD_BODY]->field_length)
|
|
||||||
{
|
|
||||||
my_error(ER_TOO_LONG_BODY, MYF(0), et->name.str);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(et->expression) && !(et->execute_at.year))
|
|
||||||
{
|
|
||||||
DBUG_PRINT("error", ("neither expression nor execute_at are set!"));
|
|
||||||
my_error(ER_EVENT_NEITHER_M_EXPR_NOR_M_AT, MYF(0));
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
((Field_timestamp *)table->field[Events::FIELD_CREATED])->set_time();
|
|
||||||
|
|
||||||
/*
|
|
||||||
evex_fill_row() calls my_error() in case of error so no need to
|
|
||||||
handle it here
|
|
||||||
*/
|
|
||||||
if ((ret= evex_fill_row(thd, table, et, false)))
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
if (table->file->ha_write_row(table->record[0]))
|
|
||||||
{
|
|
||||||
my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef USE_THIS_CODE_AS_TEMPLATE_WHEN_EVENT_REPLICATION_IS_AGREED
|
|
||||||
if (mysql_bin_log.is_open())
|
|
||||||
{
|
|
||||||
thd->clear_error();
|
|
||||||
/* Such a statement can always go directly to binlog, no trans cache */
|
|
||||||
thd->binlog_query(THD::MYSQL_QUERY_TYPE, thd->query, thd->query_length,
|
|
||||||
FALSE, FALSE);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
*rows_affected= 1;
|
|
||||||
ok:
|
|
||||||
if (dbchanged)
|
|
||||||
(void) mysql_change_db(thd, olddb, 1);
|
|
||||||
if (table)
|
|
||||||
close_thread_tables(thd);
|
|
||||||
DBUG_RETURN(EVEX_OK);
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (dbchanged)
|
|
||||||
(void) mysql_change_db(thd, olddb, 1);
|
|
||||||
if (table)
|
|
||||||
close_thread_tables(thd);
|
|
||||||
DBUG_RETURN(EVEX_GENERAL_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Used to execute ALTER EVENT. Pendant to Events::update_event().
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
db_update_event()
|
|
||||||
thd THD
|
|
||||||
sp_name the name of the event to alter
|
|
||||||
et event's data
|
|
||||||
|
|
||||||
RETURN VALUE
|
|
||||||
0 OK
|
|
||||||
EVEX_GENERAL_ERROR Error occured (my_error() called)
|
|
||||||
|
|
||||||
NOTES
|
|
||||||
sp_name is passed since this is the name of the event to
|
|
||||||
alter in case of RENAME TO.
|
|
||||||
*/
|
|
||||||
|
|
||||||
static int
|
|
||||||
db_update_event(THD *thd, Event_timed *et, sp_name *new_name)
|
|
||||||
{
|
|
||||||
CHARSET_INFO *scs= system_charset_info;
|
|
||||||
TABLE *table;
|
|
||||||
int ret= EVEX_OPEN_TABLE_FAILED;
|
|
||||||
DBUG_ENTER("db_update_event");
|
|
||||||
DBUG_PRINT("enter", ("dbname: %.*s", et->dbname.length, et->dbname.str));
|
|
||||||
DBUG_PRINT("enter", ("name: %.*s", et->name.length, et->name.str));
|
|
||||||
DBUG_PRINT("enter", ("user: %.*s", et->definer.length, et->definer.str));
|
|
||||||
if (new_name)
|
|
||||||
DBUG_PRINT("enter", ("rename to: %.*s", new_name->m_name.length,
|
|
||||||
new_name->m_name.str));
|
|
||||||
|
|
||||||
if (Events::open_event_table(thd, TL_WRITE, &table))
|
|
||||||
{
|
|
||||||
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* first look whether we overwrite */
|
|
||||||
if (new_name)
|
|
||||||
{
|
|
||||||
if (!sortcmp_lex_string(et->name, new_name->m_name, scs) &&
|
|
||||||
!sortcmp_lex_string(et->dbname, new_name->m_db, scs))
|
|
||||||
{
|
|
||||||
my_error(ER_EVENT_SAME_NAME, MYF(0), et->name.str);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!evex_db_find_event_by_name(thd,new_name->m_db,new_name->m_name,table))
|
|
||||||
{
|
|
||||||
my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->m_name.str);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
...and then if there is such an event. Don't exchange the blocks
|
|
||||||
because you will get error 120 from table handler because new_name will
|
|
||||||
overwrite the key and SE will tell us that it cannot find the already found
|
|
||||||
row (copied into record[1] later
|
|
||||||
*/
|
|
||||||
if (EVEX_KEY_NOT_FOUND == evex_db_find_event_aux(thd, et, table))
|
|
||||||
{
|
|
||||||
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), et->name.str);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
store_record(table,record[1]);
|
|
||||||
|
|
||||||
/* Don't update create on row update. */
|
|
||||||
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
|
|
||||||
|
|
||||||
/*
|
|
||||||
evex_fill_row() calls my_error() in case of error so no need to
|
|
||||||
handle it here
|
|
||||||
*/
|
|
||||||
if ((ret= evex_fill_row(thd, table, et, true)))
|
|
||||||
goto err;
|
|
||||||
|
|
||||||
if (new_name)
|
|
||||||
{
|
|
||||||
table->field[Events::FIELD_DB]->
|
|
||||||
store(new_name->m_db.str, new_name->m_db.length, scs);
|
|
||||||
table->field[Events::FIELD_NAME]->
|
|
||||||
store(new_name->m_name.str, new_name->m_name.length, scs);
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret= table->file->ha_update_row(table->record[1], table->record[0])))
|
|
||||||
{
|
|
||||||
my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret);
|
|
||||||
goto err;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* close mysql.event or we crash later when loading the event from disk */
|
|
||||||
close_thread_tables(thd);
|
|
||||||
DBUG_RETURN(0);
|
|
||||||
|
|
||||||
err:
|
|
||||||
if (table)
|
|
||||||
close_thread_tables(thd);
|
|
||||||
DBUG_RETURN(EVEX_GENERAL_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Looks for a named event in mysql.event and in case of success returns
|
|
||||||
an object will data loaded from the table.
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
db_find_event()
|
|
||||||
thd THD
|
|
||||||
name the name of the event to find
|
|
||||||
ett event's data if event is found
|
|
||||||
tbl TABLE object to use when not NULL
|
|
||||||
|
|
||||||
NOTES
|
|
||||||
1) Use sp_name for look up, return in **ett if found
|
|
||||||
2) tbl is not closed at exit
|
|
||||||
|
|
||||||
RETURN VALUE
|
|
||||||
0 ok In this case *ett is set to the event
|
|
||||||
# error *ett == 0
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
db_find_event(THD *thd, sp_name *name, Event_timed **ett, TABLE *tbl,
|
|
||||||
MEM_ROOT *root)
|
|
||||||
{
|
|
||||||
TABLE *table;
|
|
||||||
int ret;
|
|
||||||
Event_timed *et= NULL;
|
|
||||||
DBUG_ENTER("db_find_event");
|
|
||||||
DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str));
|
|
||||||
|
|
||||||
if (!root)
|
|
||||||
root= &evex_mem_root;
|
|
||||||
|
|
||||||
if (tbl)
|
|
||||||
table= tbl;
|
|
||||||
else if (Events::open_event_table(thd, TL_READ, &table))
|
|
||||||
{
|
|
||||||
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
|
||||||
ret= EVEX_GENERAL_ERROR;
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((ret= evex_db_find_event_by_name(thd, name->m_db, name->m_name, table)))
|
|
||||||
{
|
|
||||||
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name->m_name.str);
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
et= new Event_timed;
|
|
||||||
|
|
||||||
/*
|
|
||||||
1)The table should not be closed beforehand. ::load_from_row() only loads
|
|
||||||
and does not compile
|
|
||||||
|
|
||||||
2)::load_from_row() is silent on error therefore we emit error msg here
|
|
||||||
*/
|
|
||||||
if ((ret= et->load_from_row(root, table)))
|
|
||||||
{
|
|
||||||
my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
if (ret)
|
|
||||||
{
|
|
||||||
delete et;
|
|
||||||
et= 0;
|
|
||||||
}
|
|
||||||
/* don't close the table if we haven't opened it ourselves */
|
|
||||||
if (!tbl && table)
|
|
||||||
close_thread_tables(thd);
|
|
||||||
*ett= et;
|
|
||||||
DBUG_RETURN(ret);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -913,7 +283,8 @@ Events::create_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
|
|||||||
DBUG_PRINT("enter", ("name: %*s options:%d", et->name.length,
|
DBUG_PRINT("enter", ("name: %*s options:%d", et->name.length,
|
||||||
et->name.str, create_options));
|
et->name.str, create_options));
|
||||||
|
|
||||||
if (!(ret = db_create_event(thd, et,
|
if (!(ret= db_repository.
|
||||||
|
create_event(thd, et,
|
||||||
create_options & HA_LEX_CREATE_IF_NOT_EXISTS,
|
create_options & HA_LEX_CREATE_IF_NOT_EXISTS,
|
||||||
rows_affected)))
|
rows_affected)))
|
||||||
{
|
{
|
||||||
@ -960,7 +331,7 @@ Events::update_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
|
|||||||
crash later in the code when loading and compiling the new definition.
|
crash later in the code when loading and compiling the new definition.
|
||||||
Also on error conditions my_error() is called so no need to handle here
|
Also on error conditions my_error() is called so no need to handle here
|
||||||
*/
|
*/
|
||||||
if (!(ret= db_update_event(thd, et, new_name)))
|
if (!(ret= db_repository.update_event(thd, et, new_name)))
|
||||||
{
|
{
|
||||||
Event_scheduler *scheduler= Event_scheduler::get_instance();
|
Event_scheduler *scheduler= Event_scheduler::get_instance();
|
||||||
if (scheduler->initialized() &&
|
if (scheduler->initialized() &&
|
||||||
@ -973,67 +344,6 @@ Events::update_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Drops an event
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
db_drop_event()
|
|
||||||
thd THD
|
|
||||||
et event's name
|
|
||||||
drop_if_exists if set and the event not existing => warning onto the stack
|
|
||||||
rows_affected affected number of rows is returned heres
|
|
||||||
|
|
||||||
RETURN VALUE
|
|
||||||
0 OK
|
|
||||||
!0 Error (my_error() called)
|
|
||||||
*/
|
|
||||||
|
|
||||||
int db_drop_event(THD *thd, LEX_STRING db, LEX_STRING name,
|
|
||||||
bool drop_if_exists, uint *rows_affected)
|
|
||||||
{
|
|
||||||
TABLE *table;
|
|
||||||
Open_tables_state backup;
|
|
||||||
int ret;
|
|
||||||
|
|
||||||
DBUG_ENTER("db_drop_event");
|
|
||||||
DBUG_PRINT("enter", ("db=%s name=%s", db.str, name.str));
|
|
||||||
ret= EVEX_OPEN_TABLE_FAILED;
|
|
||||||
|
|
||||||
thd->reset_n_backup_open_tables_state(&backup);
|
|
||||||
if (Events::open_event_table(thd, TL_WRITE, &table))
|
|
||||||
{
|
|
||||||
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
|
|
||||||
goto done;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!(ret= evex_db_find_event_by_name(thd, db, name, table)))
|
|
||||||
{
|
|
||||||
if ((ret= table->file->ha_delete_row(table->record[0])))
|
|
||||||
my_error(ER_EVENT_CANNOT_DELETE, MYF(0));
|
|
||||||
}
|
|
||||||
else if (ret == EVEX_KEY_NOT_FOUND)
|
|
||||||
{
|
|
||||||
if (drop_if_exists)
|
|
||||||
{
|
|
||||||
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
|
|
||||||
ER_SP_DOES_NOT_EXIST, ER(ER_SP_DOES_NOT_EXIST),
|
|
||||||
"Event", name.str);
|
|
||||||
ret= 0;
|
|
||||||
} else
|
|
||||||
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
|
|
||||||
}
|
|
||||||
|
|
||||||
done:
|
|
||||||
/*
|
|
||||||
evex_drop_event() is used by Event_timed::drop therefore
|
|
||||||
we have to close our thread tables.
|
|
||||||
*/
|
|
||||||
close_thread_tables(thd);
|
|
||||||
thd->restore_backup_open_tables_state(&backup);
|
|
||||||
DBUG_RETURN(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Drops an event
|
Drops an event
|
||||||
|
|
||||||
@ -1056,14 +366,14 @@ Events::drop_event(THD *thd, sp_name *name, bool drop_if_exists,
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
DBUG_ENTER("Events::drop_event");
|
DBUG_ENTER("Events::drop_event");
|
||||||
if (!(ret= db_drop_event(thd, name->m_db, name->m_name, drop_if_exists,
|
|
||||||
rows_affected)))
|
if (!(ret= db_repository.drop_event(thd, name->m_db, name->m_name,
|
||||||
|
drop_if_exists, rows_affected)))
|
||||||
{
|
{
|
||||||
Event_scheduler *scheduler= Event_scheduler::get_instance();
|
Event_scheduler *scheduler= Event_scheduler::get_instance();
|
||||||
if (scheduler->initialized() && (ret= scheduler->drop_event(thd, name)))
|
if (scheduler->initialized() && (ret= scheduler->drop_event(thd, name)))
|
||||||
my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
|
my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0), ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
DBUG_RETURN(ret);
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1092,7 +402,7 @@ Events::show_create_event(THD *thd, sp_name *spn)
|
|||||||
DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str));
|
DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str));
|
||||||
|
|
||||||
thd->reset_n_backup_open_tables_state(&backup);
|
thd->reset_n_backup_open_tables_state(&backup);
|
||||||
ret= db_find_event(thd, spn, &et, NULL, thd->mem_root);
|
ret= db_repository.find_event(thd, spn, &et, NULL, thd->mem_root);
|
||||||
thd->restore_backup_open_tables_state(&backup);
|
thd->restore_backup_open_tables_state(&backup);
|
||||||
|
|
||||||
if (!ret)
|
if (!ret)
|
||||||
@ -1164,75 +474,13 @@ Events::drop_schema_events(THD *thd, char *db)
|
|||||||
DBUG_PRINT("enter", ("dropping events from %s", db));
|
DBUG_PRINT("enter", ("dropping events from %s", db));
|
||||||
|
|
||||||
Event_scheduler *scheduler= Event_scheduler::get_instance();
|
Event_scheduler *scheduler= Event_scheduler::get_instance();
|
||||||
if (scheduler->initialized())
|
ret= scheduler->drop_schema_events(thd, db_lex);
|
||||||
ret= scheduler->drop_schema_events(thd, &db_lex);
|
ret= db_repository.drop_schema_events(thd, db_lex);
|
||||||
else
|
|
||||||
ret= db_drop_events_from_table(thd, &db_lex);
|
|
||||||
|
|
||||||
DBUG_RETURN(ret);
|
DBUG_RETURN(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
Drops all events in the selected database, from mysql.event.
|
|
||||||
|
|
||||||
SYNOPSIS
|
|
||||||
evex_drop_db_events_from_table()
|
|
||||||
thd Thread
|
|
||||||
db Schema name
|
|
||||||
|
|
||||||
RETURN VALUE
|
|
||||||
0 OK
|
|
||||||
!0 Error from ha_delete_row
|
|
||||||
*/
|
|
||||||
|
|
||||||
int
|
|
||||||
db_drop_events_from_table(THD *thd, LEX_STRING *db)
|
|
||||||
{
|
|
||||||
int ret;
|
|
||||||
TABLE *table;
|
|
||||||
READ_RECORD read_record_info;
|
|
||||||
DBUG_ENTER("db_drop_events_from_table");
|
|
||||||
DBUG_PRINT("info", ("dropping events from %s", db->str));
|
|
||||||
|
|
||||||
if ((ret= Events::open_event_table(thd, TL_WRITE, &table)))
|
|
||||||
{
|
|
||||||
if (my_errno != ENOENT)
|
|
||||||
sql_print_error("Table mysql.event is damaged. Got error %d on open",
|
|
||||||
my_errno);
|
|
||||||
DBUG_RETURN(ret);
|
|
||||||
}
|
|
||||||
/* only enabled events are in memory, so we go now and delete the rest */
|
|
||||||
init_read_record(&read_record_info, thd, table, NULL, 1, 0);
|
|
||||||
while (!(read_record_info.read_record(&read_record_info)) && !ret)
|
|
||||||
{
|
|
||||||
char *et_db= get_field(thd->mem_root,
|
|
||||||
table->field[Events::FIELD_DB]);
|
|
||||||
|
|
||||||
LEX_STRING et_db_lex= {et_db, strlen(et_db)};
|
|
||||||
DBUG_PRINT("info", ("Current event %s.%s", et_db,
|
|
||||||
get_field(thd->mem_root,
|
|
||||||
table->field[Events::FIELD_NAME])));
|
|
||||||
|
|
||||||
if (!sortcmp_lex_string(et_db_lex, *db, system_charset_info))
|
|
||||||
{
|
|
||||||
DBUG_PRINT("info", ("Dropping"));
|
|
||||||
if ((ret= table->file->ha_delete_row(table->record[0])))
|
|
||||||
my_error(ER_EVENT_DROP_FAILED, MYF(0),
|
|
||||||
get_field(thd->mem_root,
|
|
||||||
table->field[Events::FIELD_NAME]));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
end_read_record(&read_record_info);
|
|
||||||
thd->version--; /* Force close to free memory */
|
|
||||||
|
|
||||||
close_thread_tables(thd);
|
|
||||||
|
|
||||||
DBUG_RETURN(ret);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Inits the scheduler's structures.
|
Inits the scheduler's structures.
|
||||||
|
|
||||||
@ -1251,14 +499,17 @@ int
|
|||||||
Events::init()
|
Events::init()
|
||||||
{
|
{
|
||||||
int ret= 0;
|
int ret= 0;
|
||||||
|
Event_db_repository *db_repo;
|
||||||
DBUG_ENTER("Events::init");
|
DBUG_ENTER("Events::init");
|
||||||
|
db_repo= &get_instance()->db_repository;
|
||||||
|
db_repo->init_repository();
|
||||||
|
|
||||||
/* it should be an assignment! */
|
/* it should be an assignment! */
|
||||||
if (opt_event_scheduler)
|
if (opt_event_scheduler)
|
||||||
{
|
{
|
||||||
Event_scheduler *scheduler= Event_scheduler::get_instance();
|
Event_scheduler *scheduler= Event_scheduler::get_instance();
|
||||||
DBUG_ASSERT(opt_event_scheduler == 1 || opt_event_scheduler == 2);
|
DBUG_ASSERT(opt_event_scheduler == 1 || opt_event_scheduler == 2);
|
||||||
DBUG_RETURN(scheduler->init() ||
|
DBUG_RETURN(scheduler->init(db_repo) ||
|
||||||
(opt_event_scheduler == 1? scheduler->start():
|
(opt_event_scheduler == 1? scheduler->start():
|
||||||
scheduler->start_suspended()));
|
scheduler->start_suspended()));
|
||||||
}
|
}
|
||||||
@ -1270,22 +521,23 @@ Events::init()
|
|||||||
Cleans up scheduler's resources. Called at server shutdown.
|
Cleans up scheduler's resources. Called at server shutdown.
|
||||||
|
|
||||||
SYNOPSIS
|
SYNOPSIS
|
||||||
Events::shutdown()
|
Events::deinit()
|
||||||
|
|
||||||
NOTES
|
NOTES
|
||||||
This function is not synchronized.
|
This function is not synchronized.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
void
|
void
|
||||||
Events::shutdown()
|
Events::deinit()
|
||||||
{
|
{
|
||||||
DBUG_ENTER("Events::shutdown");
|
DBUG_ENTER("Events::deinit");
|
||||||
Event_scheduler *scheduler= Event_scheduler::get_instance();
|
Event_scheduler *scheduler= Event_scheduler::get_instance();
|
||||||
if (scheduler->initialized())
|
if (scheduler->initialized())
|
||||||
{
|
{
|
||||||
scheduler->stop();
|
scheduler->stop();
|
||||||
scheduler->destroy();
|
scheduler->destroy();
|
||||||
}
|
}
|
||||||
|
get_instance()->db_repository.deinit_repository();
|
||||||
|
|
||||||
DBUG_VOID_RETURN;
|
DBUG_VOID_RETURN;
|
||||||
}
|
}
|
||||||
|
115
sql/events.h
115
sql/events.h
@ -20,65 +20,42 @@ 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
|
|
||||||
create_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
|
|
||||||
uint create_options, uint *rows_affected);
|
|
||||||
|
|
||||||
static int
|
|
||||||
update_event(THD *thd, Event_timed *et, Event_parse_data *parse_data,
|
|
||||||
sp_name *new_name, uint *rows_affected);
|
|
||||||
|
|
||||||
static int
|
|
||||||
drop_event(THD *thd, sp_name *name, bool drop_if_exists, uint *rows_affected);
|
|
||||||
|
|
||||||
static int
|
|
||||||
open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
|
|
||||||
|
|
||||||
static int
|
|
||||||
show_create_event(THD *thd, sp_name *spn);
|
|
||||||
|
|
||||||
static int
|
|
||||||
reconstruct_interval_expression(String *buf, interval_type interval,
|
|
||||||
longlong expression);
|
|
||||||
|
|
||||||
static int
|
|
||||||
drop_schema_events(THD *thd, char *db);
|
|
||||||
|
|
||||||
static int
|
|
||||||
dump_internal_status(THD *thd);
|
|
||||||
|
|
||||||
static int
|
static int
|
||||||
init();
|
init();
|
||||||
|
|
||||||
static void
|
static void
|
||||||
shutdown();
|
deinit();
|
||||||
|
|
||||||
static void
|
static void
|
||||||
init_mutexes();
|
init_mutexes();
|
||||||
@ -86,8 +63,48 @@ public:
|
|||||||
static void
|
static void
|
||||||
destroy_mutexes();
|
destroy_mutexes();
|
||||||
|
|
||||||
|
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
|
||||||
|
open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
|
||||||
|
|
||||||
|
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);
|
||||||
|
|
||||||
|
int
|
||||||
|
drop_schema_events(THD *thd, char *db);
|
||||||
|
|
||||||
|
int
|
||||||
|
dump_internal_status(THD *thd);
|
||||||
|
|
||||||
|
Event_db_repository db_repository;
|
||||||
|
|
||||||
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,94 +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;
|
|
||||||
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)
|
|||||||
}
|
}
|
||||||
(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)
|
|||||||
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)
|
|||||||
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()
|
||||||
|
@ -3847,12 +3847,13 @@ 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, 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 @@ end_with_restore_list:
|
|||||||
}
|
}
|
||||||
|
|
||||||
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 @@ end_with_restore_list:
|
|||||||
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 @@ end_with_restore_list:
|
|||||||
#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,
|
|||||||
|
|
||||||
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 */)
|
|||||||
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);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user