summaryrefslogtreecommitdiff
path: root/sql
diff options
context:
space:
mode:
authorunknown <andrey@lmy004.>2006-07-11 18:28:15 +0200
committerunknown <andrey@lmy004.>2006-07-11 18:28:15 +0200
commit42a8e2c9421854710679a0f6c3ceef6c0777ded4 (patch)
treef2fc5508efd161a1ef60e481f22fe90017197fa1 /sql
parent084f74426b5f19b47984ef298309e9a4015940c3 (diff)
downloadmariadb-git-42a8e2c9421854710679a0f6c3ceef6c0777ded4.tar.gz
WL#3337 (Event scheduler new architecture)
More small fixes to the API : use LEX_STRING instead of LEX_STRING* and if error then return bool(true) instead of error code. Merged functions. Reduced usage of sp_name. Fixed a lot of function documentation errors. Added function documentation wherever needed. Removed some unused defines and error codes. Next to come is batch rename of Event_scheduler_ng to Event_scheduler. mysql-test/r/events.result: update result mysql-test/r/events_logs_tests.result: update result mysql-test/t/events.test: more test coverage mysql-test/t/events_logs_tests.test: fix test sql/event_data_objects.cc: Cosmetics. Fix function documentation whenever needed. Move Event_job_data::compile() next to Event_job_data::execute() sql/event_data_objects.h: Remove unneeded error codes and defines Move function declarations at the end of the header sql/event_db_repository.cc: Fix function documentation. Event_db_repository::update_event() now uses LEX_STRING *-s instead of sp_name . Lower coupling. sql/event_db_repository.h: Event_db_repository::update_event() now uses LEX_STRING *-s instead of sp_name . Lower coupling. find_event -> find_named_event find_event_by_name is not used externally, merge with load_named_event() sql/event_queue.cc: LEX_STRING* to LEX_STRING Fix comments. Fix and add function documentation. Remove Event_queue::events_count() as it is unused Change get_top_for_execution_if_time() to return status code as return value and the object is in out parameter. sql/event_queue.h: LEX_STRING* to LEX_STRING Fix comments. Fix and add function documentation. Remove Event_queue::events_count() as it is unused Change get_top_for_execution_if_time() to return status code as return value and the object is in out parameter. Try to detect also lock attemptions for deadlocks. sql/event_scheduler_ng.cc: Always execute on thd->mem_root Fix according to changed API of Event_queue::get_top_for_execution_if_time() sql/events.cc: Fix function documentation. Fix code after API changes of internal Event module classes. sql/events.h: sp_name -> LEX_STRINGs sql/sql_parse.cc: Fix according to changed API of Events::show_create_event() sql/sql_yacc.yy: Don't pass NULL as third parameter to sp_head::init_strings()
Diffstat (limited to 'sql')
-rw-r--r--sql/event_data_objects.cc239
-rw-r--r--sql/event_data_objects.h52
-rw-r--r--sql/event_db_repository.cc186
-rw-r--r--sql/event_db_repository.h17
-rw-r--r--sql/event_queue.cc371
-rw-r--r--sql/event_queue.h17
-rw-r--r--sql/event_scheduler_ng.cc12
-rw-r--r--sql/events.cc129
-rw-r--r--sql/events.h4
-rw-r--r--sql/sql_parse.cc3
-rw-r--r--sql/sql_yacc.yy3
11 files changed, 488 insertions, 545 deletions
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index 0dd03e152af..8f67754a5b2 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -182,12 +182,10 @@ Event_parse_data::init_body(THD *thd)
SYNOPSIS
Event_parse_data::init_definer()
-
- RETURN VALUE
- 0 OK
+ thd Thread
*/
-int
+void
Event_parse_data::init_definer(THD *thd)
{
int definer_user_len;
@@ -216,22 +214,20 @@ Event_parse_data::init_definer(THD *thd)
definer.str[definer.length]= '\0';
DBUG_PRINT("info",("definer [%s] initted", definer.str));
- DBUG_RETURN(0);
+ DBUG_VOID_RETURN;
}
/*
- Set time for execution for one time events.
+ Sets time for execution for one-time event.
SYNOPSIS
Event_parse_data::init_execute_at()
- expr when (datetime)
+ thd Thread
RETURN VALUE
- 0 OK
- EVEX_PARSE_ERROR fix_fields failed
- EVEX_BAD_PARAMS datetime is in the past
- ER_WRONG_VALUE wrong value for execute at
+ 0 OK
+ ER_WRONG_VALUE Wrong value for execute at (reported)
*/
int
@@ -293,18 +289,16 @@ wrong_value:
/*
- Set time for execution for transient events.
+ Sets time for execution of multi-time event.s
SYNOPSIS
Event_parse_data::init_interval()
- expr how much?
- new_interval what is the interval
+ thd Thread
RETURN VALUE
- 0 OK
- EVEX_PARSE_ERROR fix_fields failed (reported)
- EVEX_BAD_PARAMS Interval is not positive (reported)
- EVEX_MICROSECOND_UNSUP Microseconds are not supported (reported)
+ 0 OK
+ EVEX_BAD_PARAMS Interval is not positive or MICROSECOND (reported)
+ ER_WRONG_VALUE Wrong value for interval (reported)
*/
int
@@ -402,12 +396,11 @@ wrong_value:
/*
- Sets activation time.
+ Sets STARTS.
SYNOPSIS
Event_parse_data::init_starts()
expr how much?
- interval what is the interval
NOTES
Note that activation time is not execution time.
@@ -418,9 +411,8 @@ wrong_value:
same time.
RETURN VALUE
- 0 OK
- EVEX_PARSE_ERROR fix_fields failed
- EVEX_BAD_PARAMS starts before now
+ 0 OK
+ ER_WRONG_VALUE Starts before now
*/
int
@@ -471,12 +463,11 @@ wrong_value:
/*
- Sets deactivation time.
+ Sets ENDS (deactivation time).
SYNOPSIS
Event_parse_data::init_ends()
thd THD
- new_ends When?
NOTES
Note that activation time is not execution time.
@@ -566,7 +557,7 @@ Event_parse_data::report_bad_value(const char *item_name, Item *bad_item)
/*
- Performs checking of the data gathered during the parsing phase.
+ Checks for validity the data gathered during the parsing phase.
SYNOPSIS
Event_parse_data::check_parse_data()
@@ -594,6 +585,7 @@ Event_parse_data::check_parse_data(THD *thd)
DBUG_RETURN(ret);
}
+
/*
Constructor
@@ -769,11 +761,8 @@ Event_timed::init()
{
DBUG_ENTER("Event_timed::init");
- body.str= comment.str= NULL;
- body.length= comment.length= 0;
-
- definer_user.str= definer_host.str= 0;
- definer_user.length= definer_host.length= 0;
+ definer_user.str= definer_host.str= body.str= comment.str= NULL;
+ definer_user.length= definer_host.length= body.length= comment.length= 0;
sql_mode= 0;
@@ -880,7 +869,7 @@ Event_queue_element::load_from_row(TABLE *table)
expression= 0;
/*
If res1 and res2 are TRUE then both fields are empty.
- Hence if ET_FIELD_EXECUTE_AT is empty there is an error.
+ Hence, if ET_FIELD_EXECUTE_AT is empty there is an error.
*/
execute_at_null= table->field[ET_FIELD_EXECUTE_AT]->is_null();
DBUG_ASSERT(!(starts_null && ends_null && !expression && execute_at_null));
@@ -1440,8 +1429,8 @@ Event_queue_element::drop(THD *thd)
uint tmp= 0;
DBUG_ENTER("Event_queue_element::drop");
- DBUG_RETURN(Events::get_instance()->drop_event(thd, dbname, name, FALSE,
- &tmp, TRUE));
+ DBUG_RETURN(Events::get_instance()->
+ drop_event(thd, dbname, name, FALSE, &tmp, TRUE));
}
@@ -1453,20 +1442,17 @@ Event_queue_element::drop(THD *thd)
thd - thread context
RETURN VALUE
- 0 OK
- EVEX_OPEN_TABLE_FAILED Error while opening mysql.event for writing
- EVEX_WRITE_ROW_FAILED On error to write to disk
-
- others return code from SE in case deletion of the event
- row failed.
+ FALSE OK
+ TRUE Error while opening mysql.event for writing or during write on disk
*/
bool
Event_queue_element::update_timing_fields(THD *thd)
{
TABLE *table;
+ Field **fields;
Open_tables_state backup;
- int ret;
+ int ret= FALSE;
DBUG_ENTER("Event_queue_element::update_timing_fields");
@@ -1480,12 +1466,12 @@ Event_queue_element::update_timing_fields(THD *thd)
if (Events::get_instance()->open_event_table(thd, TL_WRITE, &table))
{
- ret= EVEX_OPEN_TABLE_FAILED;
+ ret= TRUE;
goto done;
}
-
+ fields= table->field;
if ((ret= Events::get_instance()->db_repository->
- find_event_by_name(thd, dbname, name, table)))
+ find_named_event(thd, dbname, name, table)))
goto done;
store_record(table,record[1]);
@@ -1494,20 +1480,20 @@ Event_queue_element::update_timing_fields(THD *thd)
if (last_executed_changed)
{
- table->field[ET_FIELD_LAST_EXECUTED]->set_notnull();
- table->field[ET_FIELD_LAST_EXECUTED]->store_time(&last_executed,
+ fields[ET_FIELD_LAST_EXECUTED]->set_notnull();
+ fields[ET_FIELD_LAST_EXECUTED]->store_time(&last_executed,
MYSQL_TIMESTAMP_DATETIME);
last_executed_changed= FALSE;
}
if (status_changed)
{
- table->field[ET_FIELD_STATUS]->set_notnull();
- table->field[ET_FIELD_STATUS]->store((longlong)status, TRUE);
+ fields[ET_FIELD_STATUS]->set_notnull();
+ fields[ET_FIELD_STATUS]->store((longlong)status, TRUE);
status_changed= FALSE;
}
- if ((table->file->ha_update_row(table->record[1],table->record[0])))
- ret= EVEX_WRITE_ROW_FAILED;
+ if ((table->file->ha_update_row(table->record[1], table->record[0])))
+ ret= TRUE;
done:
close_thread_tables(thd);
@@ -1550,10 +1536,9 @@ Event_timed::get_create_event(THD *thd, String *buf)
buf->append(STRING_WITH_LEN("CREATE EVENT "));
append_identifier(thd, buf, name.str, name.length);
- buf->append(STRING_WITH_LEN(" ON SCHEDULE "));
if (expression)
{
- buf->append(STRING_WITH_LEN("EVERY "));
+ buf->append(STRING_WITH_LEN(" ON SCHEDULE EVERY "));
buf->append(expr_buf);
buf->append(' ');
LEX_STRING *ival= &interval_type_to_name[interval];
@@ -1562,7 +1547,7 @@ Event_timed::get_create_event(THD *thd, String *buf)
else
{
char dtime_buff[20*2+32];/* +32 to make my_snprintf_{8bit|ucs2} happy */
- buf->append(STRING_WITH_LEN("AT '"));
+ buf->append(STRING_WITH_LEN(" ON SCHEDULE AT '"));
/*
Pass the buffer and the second param tells fills the buffer and
returns the number of chars to copy.
@@ -1612,7 +1597,7 @@ int
Event_job_data::get_fake_create_event(THD *thd, String *buf)
{
DBUG_ENTER("Event_job_data::get_create_event");
- buf->append(STRING_WITH_LEN("CREATE EVENT test.anonymous ON SCHEDULE "
+ buf->append(STRING_WITH_LEN("CREATE EVENT anonymous ON SCHEDULE "
"EVERY 3337 HOUR DO "));
buf->append(body.str, body.length);
@@ -1621,81 +1606,6 @@ Event_job_data::get_fake_create_event(THD *thd, String *buf)
/*
- Executes the event (the underlying sp_head object);
-
- SYNOPSIS
- Event_job_data::execute()
- thd THD
- mem_root If != NULL use it to compile the event on it
-
- RETURN VALUE
- 0 success
- -99 No rights on this.dbname.str
- -100 event in execution (parallel execution is impossible)
- others retcodes of sp_head::execute_procedure()
-*/
-
-int
-Event_job_data::execute(THD *thd, MEM_ROOT *mem_root)
-{
- Security_context *save_ctx;
- /* this one is local and not needed after exec */
- Security_context security_ctx;
- int ret= 0;
-
- DBUG_ENTER("Event_job_data::execute");
- DBUG_PRINT("info", ("EXECUTING %s.%s", dbname.str, name.str));
-
- thd->change_security_context(definer_user, definer_host, dbname,
- &security_ctx, &save_ctx);
-
- if (!sphead && (ret= compile(thd, mem_root)))
- goto done;
- /*
- THD::~THD will clean this or if there is DROP DATABASE in the SP then
- it will be free there. It should not point to our buffer which is allocated
- on a mem_root.
- */
- thd->db= my_strdup(dbname.str, MYF(0));
- thd->db_length= dbname.length;
- if (!check_access(thd, EVENT_ACL,dbname.str, 0, 0, 0,is_schema_db(dbname.str)))
- {
- List<Item> empty_item_list;
- empty_item_list.empty();
- if (thd->enable_slow_log)
- sphead->m_flags|= sp_head::LOG_SLOW_STATEMENTS;
- sphead->m_flags|= sp_head::LOG_GENERAL_LOG;
-
- ret= sphead->execute_procedure(thd, &empty_item_list);
- }
- else
- {
- DBUG_PRINT("error", ("%s@%s has no rights on %s", definer_user.str,
- definer_host.str, dbname.str));
- ret= -99;
- }
- /* Will compile every time a new sp_head on different root */
- free_sp();
-
-done:
- thd->restore_security_context(save_ctx);
- /*
- 1. Don't cache sphead if allocated on another mem_root
- 2. Don't call security_ctx.destroy() because this will free our dbname.str
- name.str and definer.str
- */
- if (mem_root && sphead)
- {
- delete sphead;
- sphead= 0;
- }
- DBUG_PRINT("info", ("EXECUTED %s.%s ret=%d", dbname.str, name.str, ret));
-
- DBUG_RETURN(ret);
-}
-
-
-/*
Frees the memory of the sp_head object we hold
SYNOPSIS
Event_job_data::free_sp()
@@ -1816,7 +1726,6 @@ Event_job_data::compile(THD *thd, MEM_ROOT *mem_root)
DBUG_PRINT("note", ("success compiling %s.%s", dbname.str, name.str));
sphead= lex.sphead;
- sphead->m_db= dbname;
sphead->set_definer(definer.str, definer.length);
sphead->set_info(0, 0, &lex.sp_chistics, sql_mode);
@@ -1848,10 +1757,76 @@ done:
/*
+ Executes the event (the underlying sp_head object);
+
+ SYNOPSIS
+ Event_job_data::execute()
+ thd THD
+
+ RETURN VALUE
+ 0 success
+ -99 No rights on this.dbname.str
+ others retcodes of sp_head::execute_procedure()
+*/
+
+int
+Event_job_data::execute(THD *thd)
+{
+ Security_context *save_ctx;
+ /* this one is local and not needed after exec */
+ Security_context security_ctx;
+ int ret= 0;
+
+ DBUG_ENTER("Event_job_data::execute");
+ DBUG_PRINT("info", ("EXECUTING %s.%s", dbname.str, name.str));
+
+
+ if ((ret= compile(thd, NULL)))
+ goto done;
+
+ thd->change_security_context(definer_user, definer_host, dbname,
+ &security_ctx, &save_ctx);
+ /*
+ THD::~THD will clean this or if there is DROP DATABASE in the SP then
+ it will be free there. It should not point to our buffer which is allocated
+ on a mem_root.
+ */
+ thd->db= my_strdup(dbname.str, MYF(0));
+ thd->db_length= dbname.length;
+ if (!check_access(thd, EVENT_ACL,dbname.str, 0, 0, 0,is_schema_db(dbname.str)))
+ {
+ List<Item> empty_item_list;
+ empty_item_list.empty();
+ if (thd->enable_slow_log)
+ sphead->m_flags|= sp_head::LOG_SLOW_STATEMENTS;
+ sphead->m_flags|= sp_head::LOG_GENERAL_LOG;
+
+ ret= sphead->execute_procedure(thd, &empty_item_list);
+ }
+ else
+ {
+ DBUG_PRINT("error", ("%s@%s has no rights on %s", definer_user.str,
+ definer_host.str, dbname.str));
+ ret= -99;
+ }
+
+ thd->restore_security_context(save_ctx);
+done:
+ free_sp();
+
+ DBUG_PRINT("info", ("EXECUTED %s.%s ret=%d", dbname.str, name.str, ret));
+
+ DBUG_RETURN(ret);
+}
+
+
+/*
Checks whether two events are in the same schema
SYNOPSIS
event_basic_db_equal()
+ db Schema
+ et Compare et->dbname to `db`
RETURN VALUE
TRUE Equal
@@ -1859,9 +1834,9 @@ done:
*/
bool
-event_basic_db_equal(LEX_STRING *db, Event_basic *et)
+event_basic_db_equal(LEX_STRING db, Event_basic *et)
{
- return !sortcmp_lex_string(et->dbname, *db, system_charset_info);
+ return !sortcmp_lex_string(et->dbname, db, system_charset_info);
}
diff --git a/sql/event_data_objects.h b/sql/event_data_objects.h
index d405cafe42d..e20d698161e 100644
--- a/sql/event_data_objects.h
+++ b/sql/event_data_objects.h
@@ -17,45 +17,16 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-#define EVEX_OK 0
-#define EVEX_KEY_NOT_FOUND -1
-#define EVEX_OPEN_TABLE_FAILED -2
-#define EVEX_WRITE_ROW_FAILED -3
-#define EVEX_DELETE_ROW_FAILED -4
-#define EVEX_GET_FIELD_FAILED -5
-#define EVEX_PARSE_ERROR -6
-#define EVEX_INTERNAL_ERROR -7
-#define EVEX_NO_DB_ERROR -8
-#define EVEX_COMPILE_ERROR -19
-#define EVEX_GENERAL_ERROR -20
-#define EVEX_BAD_IDENTIFIER -21
-#define EVEX_BODY_TOO_LONG -22
-#define EVEX_BAD_PARAMS -23
-#define EVEX_NOT_RUNNING -24
-#define EVEX_MICROSECOND_UNSUP -25
-#define EVEX_CANT_KILL -26
-
-#define EVENT_EXEC_NO_MORE (1L << 0)
-#define EVENT_NOT_USED (1L << 1)
-#define EVENT_FREE_WHEN_FINISHED (1L << 2)
-
-
-#define EVENT_EXEC_STARTED 0
-#define EVENT_EXEC_ALREADY_EXEC 1
-#define EVENT_EXEC_CANT_FORK 2
+#define EVEX_GET_FIELD_FAILED -2
+#define EVEX_COMPILE_ERROR -3
+#define EVEX_GENERAL_ERROR -4
+#define EVEX_BAD_PARAMS -5
+#define EVEX_MICROSECOND_UNSUP -6
class sp_head;
class Sql_alloc;
-class Event_basic;
-/* Compares only the schema part of the identifier */
-bool
-event_basic_db_equal( LEX_STRING *db, Event_basic *et);
-
-/* Compares the whole identifier*/
-bool
-event_basic_identifier_equal(LEX_STRING db, LEX_STRING name, Event_basic *b);
class Event_basic
{
@@ -206,7 +177,7 @@ public:
load_from_row(TABLE *table);
int
- execute(THD *thd, MEM_ROOT *mem_root);
+ execute(THD *thd);
private:
int
get_fake_create_event(THD *thd, String *buf);
@@ -274,7 +245,7 @@ public:
private:
- int
+ void
init_definer(THD *thd);
void
@@ -303,4 +274,13 @@ private:
};
+/* Compares only the schema part of the identifier */
+bool
+event_basic_db_equal(LEX_STRING db, Event_basic *et);
+
+/* Compares the whole identifier*/
+bool
+event_basic_identifier_equal(LEX_STRING db, LEX_STRING name, Event_basic *b);
+
+
#endif /* _EVENT_DATA_OBJECTS_H_ */
diff --git a/sql/event_db_repository.cc b/sql/event_db_repository.cc
index 6e0ff89e453..ecf8d68e788 100644
--- a/sql/event_db_repository.cc
+++ b/sql/event_db_repository.cc
@@ -17,10 +17,10 @@
#include "mysql_priv.h"
#include "event_db_repository.h"
#include "event_data_objects.h"
-#include "sp_head.h"
-#include "sp.h"
#include "events.h"
#include "sql_show.h"
+#include "sp.h"
+#include "sp_head.h"
#define EVEX_DB_FIELD_LEN 64
#define EVEX_NAME_FIELD_LEN 64
@@ -509,8 +509,8 @@ check_parse_params(THD *thd, Event_parse_data *parse_data)
rows_affected [out] How many rows were affected
RETURN VALUE
- 0 - OK
- EVEX_GENERAL_ERROR - Failure
+ 0 OK
+ EVEX_GENERAL_ERROR Failure
DESCRIPTION
Creates an event. Relies on mysql_event_fill_row which is shared with
@@ -545,7 +545,7 @@ Event_db_repository::create_event(THD *thd, Event_parse_data *parse_data,
parse_data->name.str));
DBUG_PRINT("info", ("check existance of an event with the same name"));
- if (!find_event_by_name(thd, parse_data->dbname, parse_data->name, table))
+ if (!find_named_event(thd, parse_data->dbname, parse_data->name, table))
{
if (create_if_not)
{
@@ -623,7 +623,7 @@ ok:
(void) mysql_change_db(thd, old_db.str, 1);
if (table)
close_thread_tables(thd);
- DBUG_RETURN(EVEX_OK);
+ DBUG_RETURN(0);
err:
if (dbchanged)
@@ -652,13 +652,13 @@ err:
alter in case of RENAME TO.
*/
-int
+bool
Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
- sp_name *new_name)
+ LEX_STRING *new_dbname, LEX_STRING *new_name)
{
CHARSET_INFO *scs= system_charset_info;
TABLE *table= NULL;
- int ret= EVEX_OPEN_TABLE_FAILED;
+ int ret;
DBUG_ENTER("Event_db_repository::update_event");
if (open_event_table(thd, TL_WRITE, &table))
@@ -673,22 +673,22 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
DBUG_PRINT("info", ("dbname: %s", parse_data->dbname.str));
DBUG_PRINT("info", ("name: %s", parse_data->name.str));
DBUG_PRINT("info", ("user: %s", parse_data->definer.str));
- if (new_name)
- DBUG_PRINT("info", ("rename to: %s", new_name->m_name.str));
+ if (new_dbname)
+ DBUG_PRINT("info", ("rename to: %s@%s", new_dbname->str, new_name->str));
/* first look whether we overwrite */
- if (new_name)
+ if (new_dbname)
{
- if (!sortcmp_lex_string(parse_data->name, new_name->m_name, scs) &&
- !sortcmp_lex_string(parse_data->dbname, new_name->m_db, scs))
+ if (!sortcmp_lex_string(parse_data->name, *new_name, scs) &&
+ !sortcmp_lex_string(parse_data->dbname, *new_dbname, scs))
{
my_error(ER_EVENT_SAME_NAME, MYF(0), parse_data->name.str);
goto err;
}
- if (!find_event_by_name(thd, new_name->m_db, new_name->m_name, table))
+ if (!find_named_event(thd, *new_dbname, *new_name, table))
{
- my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->m_name.str);
+ my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->str);
goto err;
}
}
@@ -698,8 +698,7 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
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, parse_data->dbname,
- parse_data->name, table))
+ if (find_named_event(thd, parse_data->dbname, parse_data->name, table))
{
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), parse_data->name.str);
goto err;
@@ -714,22 +713,20 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
mysql_event_fill_row() calls my_error() in case of error so no need to
handle it here
*/
- if ((ret= mysql_event_fill_row(thd, table, parse_data, TRUE)))
+ if (mysql_event_fill_row(thd, table, parse_data, TRUE))
goto err;
- if (new_name)
+ if (new_dbname)
{
- 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);
+ table->field[ET_FIELD_DB]->store(new_dbname->str, new_dbname->length, scs);
+ table->field[ET_FIELD_NAME]->store(new_name->str, new_name->length, scs);
}
/* Close active transaction only if We are going to modify disk */
if (end_active_trans(thd))
goto err;
- if ((ret= table->file->ha_update_row(table->record[1], table->record[0])))
+ if (table->file->ha_update_row(table->record[1], table->record[0]))
{
my_error(ER_EVENT_STORE_FAILED, MYF(0), parse_data->name.str, ret);
goto err;
@@ -737,12 +734,12 @@ Event_db_repository::update_event(THD *thd, Event_parse_data *parse_data,
/* close mysql.event or we crash later when loading the event from disk */
close_thread_tables(thd);
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
err:
if (table)
close_thread_tables(thd);
- DBUG_RETURN(EVEX_GENERAL_ERROR);
+ DBUG_RETURN(TRUE);
}
@@ -759,11 +756,11 @@ err:
rows_affected [out] Affected number of rows is returned heres
RETURN VALUE
- 0 OK
- !0 Error (my_error() called)
+ FALSE OK
+ TRUE Error (reported)
*/
-int
+bool
Event_db_repository::drop_event(THD *thd, LEX_STRING db, LEX_STRING name,
bool drop_if_exists, uint *rows_affected)
{
@@ -772,26 +769,24 @@ Event_db_repository::drop_event(THD *thd, LEX_STRING db, LEX_STRING name,
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;
+ DBUG_PRINT("enter", ("%s@%s", db.str, name.str));
thd->reset_n_backup_open_tables_state(&backup);
- if (open_event_table(thd, TL_WRITE, &table))
+ if ((ret= open_event_table(thd, TL_WRITE, &table)))
{
my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
goto done;
}
- switch ((ret= find_event_by_name(thd, db, name, table))) {
- case 0:
+ if (!(ret= find_named_event(thd, db, name, table)))
+ {
/* Close active transaction only if we are actually going to modify disk */
- if ((ret= end_active_trans(thd)))
- break;
-
- if ((ret= table->file->ha_delete_row(table->record[0])))
+ if (!(ret= end_active_trans(thd)) &&
+ (ret= table->file->ha_delete_row(table->record[0])))
my_error(ER_EVENT_CANNOT_DELETE, MYF(0));
- break;
- case EVEX_KEY_NOT_FOUND:
+ }
+ else
+ {
if (drop_if_exists)
{
push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
@@ -800,15 +795,13 @@ Event_db_repository::drop_event(THD *thd, LEX_STRING db, LEX_STRING name,
ret= 0;
} else
my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
- break;
- default:
- ;
}
done:
if (table)
close_thread_tables(thd);
thd->restore_backup_open_tables_state(&backup);
+
DBUG_RETURN(ret);
}
@@ -818,23 +811,23 @@ done:
is stored.
SYNOPSIS
- Event_db_repository::find_event_by_name()
+ Event_db_repository::find_named_event()
thd Thread
db Schema
name Event name
table Opened mysql.event
RETURN VALUE
- 0 OK
- EVEX_KEY_NOT_FOUND No such event
+ FALSE OK
+ TRUE No such event
*/
-int
-Event_db_repository::find_event_by_name(THD *thd, LEX_STRING db,
- LEX_STRING name, TABLE *table)
+bool
+Event_db_repository::find_named_event(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_ENTER("Event_db_repository::find_named_event");
DBUG_PRINT("enter", ("name: %.*s", name.length, name.str));
/*
@@ -846,7 +839,7 @@ Event_db_repository::find_event_by_name(THD *thd, LEX_STRING db,
*/
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);
+ DBUG_RETURN(TRUE);
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);
@@ -858,11 +851,11 @@ Event_db_repository::find_event_by_name(THD *thd, LEX_STRING db,
HA_READ_KEY_EXACT))
{
DBUG_PRINT("info", ("Row not found"));
- DBUG_RETURN(EVEX_KEY_NOT_FOUND);
+ DBUG_RETURN(TRUE);
}
DBUG_PRINT("info", ("Row found!"));
- DBUG_RETURN(0);
+ DBUG_RETURN(FALSE);
}
@@ -945,67 +938,6 @@ Event_db_repository::drop_events_by_field(THD *thd,
/*
- Looks for a named event in mysql.event and in case of success returns
- an object will data loaded from the table.
-
- SYNOPSIS
- Event_db_repository::find_event()
- thd [in] THD
- name [in] The name of the event to find
- ett [out] Event's data if event is found
- tbl [in] 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, LEX_STRING dbname, LEX_STRING name,
- Event_basic *et)
-{
- TABLE *table= NULL;
- int ret;
- DBUG_ENTER("Event_db_repository::find_event");
- DBUG_PRINT("enter", ("name: %*s", name.length, name.str));
-
- if (open_event_table(thd, TL_READ, &table))
- {
- my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
- ret= EVEX_GENERAL_ERROR;
- goto done;
- }
-
- if ((ret= find_event_by_name(thd, dbname, name, table)))
- {
- my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
- goto done;
- }
- /*
- 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(table)))
- {
- my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
- goto done;
- }
-
-done:
- if (table)
- close_thread_tables(thd);
-
- 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.
@@ -1017,14 +949,15 @@ done:
etn_new [out] The loaded event
RETURN VALUE
- OP_OK OK
- OP_LOAD_ERROR Error during loading from disk
+ FALSE OK
+ TRUE Error (reported)
*/
-int
+bool
Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname,
LEX_STRING name, Event_basic *etn)
{
+ TABLE *table= NULL;
int ret= 0;
Open_tables_state backup;
@@ -1032,12 +965,19 @@ Event_db_repository::load_named_event(THD *thd, LEX_STRING dbname,
DBUG_PRINT("enter",("thd=0x%lx name:%*s",thd, name.length, name.str));
thd->reset_n_backup_open_tables_state(&backup);
- /* No need to use my_error() here because find_event() has done it */
- ret= find_event(thd, dbname, name, etn);
+
+ if ((ret= open_event_table(thd, TL_READ, &table)))
+ my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0));
+ else if ((ret= find_named_event(thd, dbname, name, table)))
+ my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name.str);
+ else if ((ret= etn->load_from_row(table)))
+ my_error(ER_CANNOT_LOAD_FROM_TABLE, MYF(0), "event");
+
+ if (table)
+ close_thread_tables(thd);
+
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);
- DBUG_RETURN(OP_OK);
+ DBUG_RETURN(ret);
}
diff --git a/sql/event_db_repository.h b/sql/event_db_repository.h
index d13538ce10b..dce447a71e8 100644
--- a/sql/event_db_repository.h
+++ b/sql/event_db_repository.h
@@ -16,6 +16,8 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+#define EVEX_OPEN_TABLE_FAILED -1
+
enum enum_events_table_field
{
ET_FIELD_DB = 0,
@@ -60,24 +62,23 @@ public:
create_event(THD *thd, Event_parse_data *parse_data, my_bool create_if_not,
uint *rows_affected);
- int
- update_event(THD *thd, Event_parse_data *parse_data, sp_name *new_name);
+ bool
+ update_event(THD *thd, Event_parse_data *parse_data, LEX_STRING *new_dbname,
+ LEX_STRING *new_name);
- int
+ bool
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
- find_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_basic *et);
+ bool
+ find_named_event(THD *thd, LEX_STRING db, LEX_STRING name, TABLE *table);
- int
+ bool
load_named_event(THD *thd, LEX_STRING dbname, LEX_STRING name, Event_basic *et);
- int
- find_event_by_name(THD *thd, LEX_STRING db, LEX_STRING name, TABLE *table);
int
open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
diff --git a/sql/event_queue.cc b/sql/event_queue.cc
index 0fbde5d8910..63dee303fc2 100644
--- a/sql/event_queue.cc
+++ b/sql/event_queue.cc
@@ -15,13 +15,14 @@
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include "mysql_priv.h"
-#include "events.h"
-#include "event_scheduler_ng.h"
#include "event_queue.h"
#include "event_data_objects.h"
#include "event_db_repository.h"
-#include "sp_head.h"
+#include "event_scheduler_ng.h"
+
+#define EVENT_QUEUE_INITIAL_SIZE 30
+#define EVENT_QUEUE_EXTENT 30
#ifdef __GNUC__
#if __GNUC__ >= 2
@@ -36,21 +37,20 @@
/*
- Compares the execute_at members of 2 Event_queue_element instances.
+ Compares the execute_at members of two Event_queue_element instances.
Used as callback for the prioritized queue when shifting
elements inside.
SYNOPSIS
event_queue_element_data_compare_q()
-
- vptr - not used (set it to NULL)
- a - first Event_queue_element object
- b - second Event_queue_element object
+ vptr Not used (set it to NULL)
+ a First Event_queue_element object
+ b Second Event_queue_element object
RETURN VALUE
- -1 - a->execute_at < b->execute_at
- 0 - a->execute_at == b->execute_at
- 1 - a->execute_at > b->execute_at
+ -1 a->execute_at < b->execute_at
+ 0 a->execute_at == b->execute_at
+ 1 a->execute_at > b->execute_at
NOTES
execute_at.second_part is not considered during comparison
@@ -73,9 +73,13 @@ event_queue_element_compare_q(void *vptr, byte* a, byte *b)
Event_queue::Event_queue()
{
- mutex_last_unlocked_at_line= mutex_last_locked_at_line= 0;
- mutex_last_unlocked_in_func= mutex_last_locked_in_func= "";
- mutex_queue_data_locked= FALSE;
+ mutex_last_unlocked_at_line= mutex_last_locked_at_line=
+ mutex_last_attempted_lock_at_line= 0;
+
+ mutex_last_unlocked_in_func= mutex_last_locked_in_func=
+ mutex_last_attempted_lock_in_func= "";
+
+ mutex_queue_data_locked= mutex_queue_data_attempting_lock= FALSE;
}
@@ -108,24 +112,6 @@ Event_queue::deinit_mutexes()
/*
- Signals the main scheduler thread that the queue has changed
- its state.
-
- SYNOPSIS
- Event_queue::notify_observers()
-*/
-
-void
-Event_queue::notify_observers()
-{
- DBUG_ENTER("Event_queue::notify_observers");
- DBUG_PRINT("info", ("Signalling change of the queue"));
- scheduler->queue_changed();
- DBUG_VOID_RETURN;
-}
-
-
-/*
Inits the queue
SYNOPSIS
@@ -148,8 +134,9 @@ Event_queue::init_queue(Event_db_repository *db_repo, Event_scheduler_ng *sched)
db_repository= db_repo;
scheduler= sched;
- if (init_queue_ex(&queue, 30 /*num_el*/, 0 /*offset*/, 0 /*smallest_on_top*/,
- event_queue_element_compare_q, NULL, 30 /*auto_extent*/))
+ if (init_queue_ex(&queue, EVENT_QUEUE_INITIAL_SIZE , 0 /*offset*/,
+ 0 /*smallest_on_top*/, event_queue_element_compare_q,
+ NULL, EVENT_QUEUE_EXTENT))
{
sql_print_error("SCHEDULER: Can't initialize the execution queue");
ret= TRUE;
@@ -172,7 +159,8 @@ end:
/*
- Deinits the queue
+ Deinits the queue. Remove all elements from it and destroys them
+ too.
SYNOPSIS
Event_queue::deinit_queue()
@@ -193,12 +181,12 @@ Event_queue::deinit_queue()
/*
- Creates an event in the scheduler queue
+ Adds an event to the queue.
SYNOPSIS
Event_queue::create_event()
- et The event to add
- check_existence Whether to check if already loaded.
+ dbname The schema of the new event
+ name The name of the new event
RETURN VALUE
OP_OK OK or scheduler not working
@@ -209,21 +197,21 @@ int
Event_queue::create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
{
int res;
- Event_queue_element *element_new;
+ Event_queue_element *new_element;
DBUG_ENTER("Event_queue::create_event");
DBUG_PRINT("enter", ("thd=0x%lx et=%s.%s",thd, dbname.str, name.str));
- element_new= new Event_queue_element();
- res= db_repository->load_named_event(thd, dbname, name, element_new);
- if (res || element_new->status == Event_queue_element::DISABLED)
- delete element_new;
+ new_element= new Event_queue_element();
+ res= db_repository->load_named_event(thd, dbname, name, new_element);
+ if (res || new_element->status == Event_queue_element::DISABLED)
+ delete new_element;
else
{
- element_new->compute_next_execution_time();
+ new_element->compute_next_execution_time();
LOCK_QUEUE_DATA();
- DBUG_PRINT("info", ("new event in the queue 0x%lx", element_new));
- queue_insert_safe(&queue, (byte *) element_new);
+ DBUG_PRINT("info", ("new event in the queue 0x%lx", new_element));
+ queue_insert_safe(&queue, (byte *) new_element);
UNLOCK_QUEUE_DATA();
notify_observers();
@@ -254,53 +242,54 @@ Event_queue::update_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
LEX_STRING *new_schema, LEX_STRING *new_name)
{
int res;
- Event_queue_element *element_old= NULL,
- *element_new;
+ Event_queue_element *old_element= NULL,
+ *new_element;
DBUG_ENTER("Event_queue::update_event");
DBUG_PRINT("enter", ("thd=0x%lx et=[%s.%s]", thd, dbname.str, name.str));
- element_new= new Event_queue_element();
+ new_element= new Event_queue_element();
res= db_repository->load_named_event(thd, new_schema? *new_schema:dbname,
- new_name? *new_name:name, element_new);
+ new_name? *new_name:name, new_element);
if (res)
{
- delete element_new;
+ delete new_element;
goto end;
}
- else if (element_new->status == Event_queue_element::DISABLED)
+ else if (new_element->status == Event_queue_element::DISABLED)
{
DBUG_PRINT("info", ("The event is disabled."));
/*
Destroy the object but don't skip to end: because we may have to remove
object from the cache.
*/
- delete element_new;
- element_new= NULL;
+ delete new_element;
+ new_element= NULL;
}
else
- element_new->compute_next_execution_time();
+ new_element->compute_next_execution_time();
LOCK_QUEUE_DATA();
- if (!(element_old= find_event(dbname, name, TRUE)))
+ if (!(old_element= find_n_remove_event(dbname, name)))
{
DBUG_PRINT("info", ("%s.%s not cached, probably was DISABLED",
dbname.str, name.str));
}
/* If not disabled event */
- if (element_new)
+ if (new_element)
{
DBUG_PRINT("info", ("new event in the Q 0x%lx old 0x%lx",
- element_new, element_old));
- queue_insert_safe(&queue, (byte *) element_new);
+ new_element, old_element));
+ queue_insert_safe(&queue, (byte *) new_element);
}
UNLOCK_QUEUE_DATA();
- notify_observers();
+ if (new_element)
+ notify_observers();
- if (element_old)
- delete element_old;
+ if (old_element)
+ delete old_element;
end:
DBUG_PRINT("info", ("res=%d", res));
DBUG_RETURN(res);
@@ -326,7 +315,7 @@ Event_queue::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
DBUG_PRINT("enter", ("thd=0x%lx name=0x%lx", thd, name));
LOCK_QUEUE_DATA();
- element= find_event(dbname, name, TRUE);
+ element= find_n_remove_event(dbname, name);
UNLOCK_QUEUE_DATA();
if (element)
@@ -344,48 +333,6 @@ Event_queue::drop_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
/*
- Searches for an event in the queue
-
- SYNOPSIS
- Event_queue::find_event()
- db The schema of the event to find
- name The event to find
- remove_from_q If found whether to remove from the Q
-
- RETURN VALUE
- NULL Not found
- otherwise Address
-
- NOTE
- The caller should do the locking also the caller is responsible for
- actual signalling in case an event is removed from the queue
- (signalling COND_new_work for instance).
-*/
-
-Event_queue_element *
-Event_queue::find_event(LEX_STRING db, LEX_STRING name, bool remove_from_q)
-{
- uint i;
- DBUG_ENTER("Event_queue::find_event");
-
- for (i= 0; i < queue.elements; ++i)
- {
- Event_queue_element *et= (Event_queue_element *) queue_element(&queue, i);
- DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?", db.str, name.str,
- et->dbname.str, et->name.str));
- if (event_basic_identifier_equal(db, name, et))
- {
- if (remove_from_q)
- queue_remove(&queue, i);
- DBUG_RETURN(et);
- }
- }
-
- DBUG_RETURN(NULL);
-}
-
-
-/*
Drops all events from the in-memory queue and disk that match
certain pattern evaluated by a comparator function
@@ -404,7 +351,7 @@ Event_queue::find_event(LEX_STRING db, LEX_STRING name, bool remove_from_q)
void
Event_queue::drop_matching_events(THD *thd, LEX_STRING pattern,
- bool (*comparator)(LEX_STRING *, Event_basic *))
+ bool (*comparator)(LEX_STRING, Event_basic *))
{
DBUG_ENTER("Event_queue::drop_matching_events");
DBUG_PRINT("enter", ("pattern=%*s state=%d", pattern.length, pattern.str));
@@ -414,7 +361,7 @@ Event_queue::drop_matching_events(THD *thd, LEX_STRING pattern,
{
Event_queue_element *et= (Event_queue_element *) queue_element(&queue, i);
DBUG_PRINT("info", ("[%s.%s]?", et->dbname.str, et->name.str));
- if (comparator(&pattern, et))
+ if (comparator(pattern, et))
{
/*
The queue is ordered. If we remove an element, then all elements after
@@ -468,25 +415,59 @@ Event_queue::drop_schema_events(THD *thd, LEX_STRING schema)
/*
- Returns the number of elements in the queue
+ Signals the observers (the main scheduler thread) that the
+ state of the queue has been changed.
SYNOPSIS
- Event_queue::events_count()
+ Event_queue::notify_observers()
+*/
+
+void
+Event_queue::notify_observers()
+{
+ DBUG_ENTER("Event_queue::notify_observers");
+ DBUG_PRINT("info", ("Signalling change of the queue"));
+ scheduler->queue_changed();
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Searches for an event in the queue
+
+ SYNOPSIS
+ Event_queue::find_n_remove_event()
+ db The schema of the event to find
+ name The event to find
RETURN VALUE
- Number of Event_queue_element objects in the queue
+ NULL Not found
+ otherwise Address
+
+ NOTE
+ The caller should do the locking also the caller is responsible for
+ actual signalling in case an event is removed from the queue.
*/
-uint
-Event_queue::events_count()
+Event_queue_element *
+Event_queue::find_n_remove_event(LEX_STRING db, LEX_STRING name)
{
- uint n;
- DBUG_ENTER("Event_scheduler::events_count");
- LOCK_QUEUE_DATA();
- n= queue.elements;
- UNLOCK_QUEUE_DATA();
- DBUG_PRINT("info", ("n=%u", n));
- DBUG_RETURN(n);
+ uint i;
+ DBUG_ENTER("Event_queue::find_n_remove_event");
+
+ for (i= 0; i < queue.elements; ++i)
+ {
+ Event_queue_element *et= (Event_queue_element *) queue_element(&queue, i);
+ DBUG_PRINT("info", ("[%s.%s]==[%s.%s]?", db.str, name.str,
+ et->dbname.str, et->name.str));
+ if (event_basic_identifier_equal(db, name, et))
+ {
+ queue_remove(&queue, i);
+ DBUG_RETURN(et);
+ }
+ }
+
+ DBUG_RETURN(NULL);
}
@@ -620,6 +601,11 @@ end:
SYNOPSIS
Event_queue::check_system_tables()
+ thd Thread
+
+ RETURN VALUE
+ FALSE OK
+ TRUE Error
*/
bool
@@ -738,6 +724,14 @@ Event_queue::empty_queue()
}
+/*
+ Dumps the queue to the trace log.
+
+ SYNOPSIS
+ Event_queue::dbug_dump_queue()
+ now Current timestamp
+*/
+
inline void
Event_queue::dbug_dump_queue(time_t now)
{
@@ -761,12 +755,37 @@ Event_queue::dbug_dump_queue(time_t now)
#endif
}
-Event_job_data *
+
+/*
+ Checks whether the top of the queue is elligible for execution and
+ returns an Event_job_data instance in case it should be executed.
+ `now` is compared against `execute_at` of the top element in the queue.
+
+ SYNOPSIS
+ Event_queue::dbug_dump_queue()
+ thd [in] Thread
+ now [in] Current timestamp
+ job_data [out] The object to execute
+ abstime [out] Time to sleep
+
+ RETURN VALUE
+ FALSE No error. If *job_data==NULL then top not elligible for execution.
+ Could be that there is no top. If abstime->tv_sec is set to value
+ greater than zero then use abstime with pthread_cond_timedwait().
+ If abstime->tv_sec is zero then sleep with pthread_cond_wait().
+ abstime->tv_nsec is always zero.
+ TRUE Error
+
+*/
+
+bool
Event_queue::get_top_for_execution_if_time(THD *thd, time_t now,
+ Event_job_data **job_data,
struct timespec *abstime)
{
+ bool ret= FALSE;
struct timespec top_time;
- Event_job_data *et_new= NULL;
+ *job_data= NULL;
DBUG_ENTER("Event_queue::get_top_for_execution_if_time");
DBUG_PRINT("enter", ("thd=0x%lx now=%d", thd, now));
abstime->tv_nsec= 0;
@@ -780,56 +799,58 @@ Event_queue::get_top_for_execution_if_time(THD *thd, time_t now,
}
dbug_dump_queue(now);
- Event_queue_element *et= ((Event_queue_element*) queue_element(&queue, 0));
- top_time.tv_sec= sec_since_epoch_TIME(&et->execute_at);
+ Event_queue_element *top= ((Event_queue_element*) queue_element(&queue, 0));
- if (top_time.tv_sec <= now)
- {
- DBUG_PRINT("info", ("Ready for execution"));
- abstime->tv_sec= 0;
- et_new= new Event_job_data();
- if ((res= db_repository->load_named_event(thd, et->dbname, et->name,
- et_new)))
- {
- delete et_new;
- et_new= NULL;
- DBUG_ASSERT(0);
- break;
- }
-
- et->mark_last_executed(thd);
- if (et->compute_next_execution_time())
- et->status= Event_queue_element::DISABLED;
- DBUG_PRINT("info", ("event's status is %d", et->status));
-
- et->update_timing_fields(thd);
- if (((et->execute_at.year && !et->expression) || et->execute_at_null) ||
- (et->status == Event_queue_element::DISABLED))
- {
- DBUG_PRINT("info", ("removing from the queue"));
- if (et->dropped)
- et->drop(thd);
- delete et;
- queue_remove(&queue, 0);
- }
- else
- queue_replaced(&queue);
- }
- else
+ top_time.tv_sec= sec_since_epoch_TIME(&top->execute_at);
+
+ if (top_time.tv_sec > now)
{
abstime->tv_sec= top_time.tv_sec;
DBUG_PRINT("info", ("Have to wait %d till %d", abstime->tv_sec - now,
abstime->tv_sec));
+ break;
}
+
+ DBUG_PRINT("info", ("Ready for execution"));
+ abstime->tv_sec= 0;
+ *job_data= new Event_job_data();
+ if ((res= db_repository->load_named_event(thd, top->dbname, top->name,
+ *job_data)))
+ {
+ delete *job_data;
+ *job_data= NULL;
+ ret= TRUE;
+ break;
+ }
+
+ top->mark_last_executed(thd);
+ if (top->compute_next_execution_time())
+ top->status= Event_queue_element::DISABLED;
+ DBUG_PRINT("info", ("event's status is %d", top->status));
+
+ top->update_timing_fields(thd);
+ if (((top->execute_at.year && !top->expression) || top->execute_at_null) ||
+ (top->status == Event_queue_element::DISABLED))
+ {
+ DBUG_PRINT("info", ("removing from the queue"));
+ if (top->dropped)
+ top->drop(thd);
+ delete top;
+ queue_remove(&queue, 0);
+ }
+ else
+ queue_replaced(&queue);
} while (0);
UNLOCK_QUEUE_DATA();
- DBUG_PRINT("info", ("returning. et_new=0x%lx abstime.tv_sec=%d ", et_new,
- abstime->tv_sec));
- if (et_new)
- DBUG_PRINT("info", ("db=%s name=%s definer=%s",
- et_new->dbname.str, et_new->name.str, et_new->definer.str));
- DBUG_RETURN(et_new);
+ DBUG_PRINT("info", ("returning %d. et_new=0x%lx abstime.tv_sec=%d ",
+ ret, *job_data, abstime->tv_sec));
+
+ if (*job_data)
+ DBUG_PRINT("info", ("db=%s name=%s definer=%s", (*job_data)->dbname.str,
+ (*job_data)->name.str, (*job_data)->definer.str));
+
+ DBUG_RETURN(ret);
}
@@ -848,10 +869,18 @@ Event_queue::lock_data(const char *func, uint line)
{
DBUG_ENTER("Event_queue::lock_data");
DBUG_PRINT("enter", ("func=%s line=%u", func, line));
+ mutex_last_attempted_lock_in_func= func;
+ mutex_last_attempted_lock_at_line= line;
+ mutex_queue_data_attempting_lock= TRUE;
pthread_mutex_lock(&LOCK_event_queue);
+ mutex_last_attempted_lock_in_func= "";
+ mutex_last_attempted_lock_at_line= 0;
+ mutex_queue_data_attempting_lock= FALSE;
+
mutex_last_locked_in_func= func;
mutex_last_locked_at_line= line;
mutex_queue_data_locked= TRUE;
+
DBUG_VOID_RETURN;
}
@@ -921,6 +950,13 @@ Event_queue::dump_internal_status(THD *thd)
protocol->store(&int_string);
ret= protocol->write();
+ /* queue_data_attempting_lock */
+ protocol->prepare_for_resend();
+ protocol->store(STRING_WITH_LEN("queue data attempting lock"), scs);
+ int_string.set((longlong) mutex_queue_data_attempting_lock, scs);
+ protocol->store(&int_string);
+ ret= protocol->write();
+
/* last locked at*/
protocol->prepare_for_resend();
protocol->store(STRING_WITH_LEN("queue last locked at"), scs);
@@ -940,6 +976,17 @@ Event_queue::dump_internal_status(THD *thd)
mutex_last_unlocked_at_line));
protocol->store(&tmp_string);
ret= protocol->write();
+
+ /* last attempted lock at*/
+ protocol->prepare_for_resend();
+ protocol->store(STRING_WITH_LEN("queue last attempted lock at"), scs);
+ tmp_string.length(scs->cset->snprintf(scs, (char*) tmp_string.ptr(),
+ tmp_string.alloced_length(), "%s::%d",
+ mutex_last_attempted_lock_in_func,
+ mutex_last_attempted_lock_at_line));
+ protocol->store(&tmp_string);
+ ret= protocol->write();
+
#endif
DBUG_RETURN(FALSE);
}
diff --git a/sql/event_queue.h b/sql/event_queue.h
index 142a866e5ba..15a28b4103d 100644
--- a/sql/event_queue.h
+++ b/sql/event_queue.h
@@ -16,7 +16,6 @@
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
-class sp_name;
class Event_basic;
class Event_db_repository;
class Event_job_data;
@@ -57,31 +56,28 @@ public:
void
drop_schema_events(THD *thd, LEX_STRING schema);
- uint
- events_count();
-
static bool
check_system_tables(THD *thd);
void
recalculate_activation_times(THD *thd);
- Event_job_data *
- get_top_for_execution_if_time(THD *thd, time_t now, struct timespec *abstime);
-
+ bool
+ get_top_for_execution_if_time(THD *thd, time_t now, Event_job_data **job_data,
+ struct timespec *abstime);
bool
dump_internal_status(THD *thd);
protected:
Event_queue_element *
- find_event(LEX_STRING db, LEX_STRING name, bool remove_from_q);
+ find_n_remove_event(LEX_STRING db, LEX_STRING name);
int
load_events_from_db(THD *thd);
void
drop_matching_events(THD *thd, LEX_STRING pattern,
- bool (*)(LEX_STRING *, Event_basic *));
+ bool (*)(LEX_STRING, Event_basic *));
void
empty_queue();
@@ -93,9 +89,12 @@ protected:
uint mutex_last_locked_at_line;
uint mutex_last_unlocked_at_line;
+ uint mutex_last_attempted_lock_at_line;
const char* mutex_last_locked_in_func;
const char* mutex_last_unlocked_in_func;
+ const char* mutex_last_attempted_lock_in_func;
bool mutex_queue_data_locked;
+ bool mutex_queue_data_attempting_lock;
/* helper functions for working with mutexes & conditionals */
void
diff --git a/sql/event_scheduler_ng.cc b/sql/event_scheduler_ng.cc
index 54261cf902e..1f004d0b05e 100644
--- a/sql/event_scheduler_ng.cc
+++ b/sql/event_scheduler_ng.cc
@@ -176,6 +176,7 @@ deinit_event_thread(THD *thd)
my_thread_end();
}
+
/*
Function that executes the scheduler,
@@ -271,7 +272,7 @@ event_worker_ng_thread(void *arg)
thd->enable_slow_log= TRUE;
- ret= event->execute(thd, thd->mem_root);
+ ret= event->execute(thd);
evex_print_warnings(thd, event);
@@ -506,8 +507,13 @@ Event_scheduler_ng::run(THD *thd)
{
thd->end_time();
/* Gets a minimized version */
- job_data= queue->
- get_top_for_execution_if_time(thd, thd->query_start(), &abstime);
+ if (queue->get_top_for_execution_if_time(thd, thd->query_start(),
+ &job_data, &abstime))
+ {
+ sql_print_information("SCHEDULER: Serious error during getting next"
+ " event to execute. Stopping.");
+ break;
+ }
DBUG_PRINT("info", ("get_top returned job_data=0x%lx now=%d "
"abs_time.tv_sec=%d",
diff --git a/sql/events.cc b/sql/events.cc
index d3eb4bcd128..cfb7a067d63 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -41,10 +41,6 @@
- Add logging to file
-Warning:
- - For now parallel execution is not possible because the same sp_head cannot
- be executed few times!!! There is still no lock attached to particular
- event.
*/
@@ -84,18 +80,14 @@ ulong Events::opt_event_scheduler= 2;
SYNOPSIS
sortcmp_lex_string()
-
- s - first LEX_STRING
- t - second LEX_STRING
- cs - charset
+ s First LEX_STRING
+ t Second LEX_STRING
+ cs Charset
RETURN VALUE
- -1 - s < t
- 0 - s == t
- 1 - s > t
-
- Notes
- TIME.second_part is not considered during comparison
+ -1 s < t
+ 0 s == t
+ 1 s > t
*/
int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
@@ -104,6 +96,7 @@ int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs)
(uchar *) t.str,t.length, 0);
}
+
/*
Accessor for the singleton instance.
@@ -131,13 +124,13 @@ Events::get_instance()
SYNOPSIS
Events::reconstruct_interval_expression()
- buf - preallocated String buffer to add the value to
- interval - the interval type (for instance YEAR_MONTH)
- expression - the value in the lowest entity
+ buf Preallocated String buffer to add the value to
+ interval The interval type (for instance YEAR_MONTH)
+ expression The value in the lowest entity
RETURN VALUE
- 0 - OK
- 1 - Error
+ 0 OK
+ 1 Error
*/
int
@@ -256,7 +249,7 @@ common_1_lev_code:
/*
- Open mysql.event table for read
+ Opens mysql.event table with specified lock
SYNOPSIS
Events::open_event_table()
@@ -283,11 +276,10 @@ Events::open_event_table(THD *thd, enum thr_lock_type lock_type,
SYNOPSIS
Events::create_event()
- thd THD
- et event's data
- create_options Options specified when in the query. We are
- interested whether there is IF NOT EXISTS
- rows_affected How many rows were affected
+ thd [in] THD
+ et [in] Event's data from parsing stage
+ if_not_exists [in] Whether IF NOT EXISTS was specified in the DDL
+ rows_affected [out] How many rows were affected
RETURN VALUE
0 OK
@@ -328,9 +320,10 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, bool if_not_exists,
SYNOPSIS
Events::update_event()
- thd THD
- et Event's data from parsing stage
- new_name Set in case of RENAME TO.
+ thd [in] THD
+ et [in] Event's data from parsing stage
+ rename_to [in] Set in case of RENAME TO.
+ rows_affected [out] How many rows were affected.
RETURN VALUE
0 OK
@@ -338,26 +331,25 @@ Events::create_event(THD *thd, Event_parse_data *parse_data, bool if_not_exists,
NOTES
et contains data about dbname and event name.
- new_name is the new name of the event, if not null (this means
- that RENAME TO was specified in the query)
+ new_name is the new name of the event, if not null this means
+ that RENAME TO was specified in the query
*/
int
-Events::update_event(THD *thd, Event_parse_data *parse_data, sp_name *new_name,
+Events::update_event(THD *thd, Event_parse_data *parse_data, sp_name *rename_to,
uint *rows_affected)
{
int ret;
DBUG_ENTER("Events::update_event");
+ LEX_STRING *new_dbname= rename_to? &rename_to->m_db: NULL;
+ LEX_STRING *new_name= rename_to? &rename_to->m_name: NULL;
pthread_mutex_lock(&LOCK_event_metadata);
/* On error conditions my_error() is called so no need to handle here */
- if (!(ret= db_repository->update_event(thd, parse_data, new_name)))
+ if (!(ret= db_repository->update_event(thd, parse_data, new_dbname, new_name)))
{
- if ((ret= event_queue->update_event(thd,
- parse_data->dbname,
- parse_data->name,
- new_name? &new_name->m_db: NULL,
- new_name? &new_name->m_name: NULL)))
+ if ((ret= event_queue->update_event(thd, parse_data->dbname,
+ parse_data->name, new_dbname, new_name)))
{
DBUG_ASSERT(ret == OP_LOAD_ERROR);
my_error(ER_EVENT_MODIFY_QUEUE_ERROR, MYF(0));
@@ -374,16 +366,16 @@ Events::update_event(THD *thd, Event_parse_data *parse_data, sp_name *new_name,
SYNOPSIS
Events::drop_event()
- thd THD
- dbname Event's schema
- name Event's name
- if_exists When set and the event does not exist => warning onto
- the stack
- rows_affected Affected number of rows is returned heres
- only_from_disk Whether to remove the event from the queue too. In case
- of Event_job_data::drop() it's needed to do only disk
- drop because Event_queue will handle removal from memory
- queue.
+ thd [in] THD
+ dbname [in] Event's schema
+ name [in] Event's name
+ if_exists [in] When set and the event does not exist =>
+ warning onto the stack
+ rows_affected [out] Affected number of rows is returned here
+ only_from_disk [in] Whether to remove the event from the queue too.
+ In case of Event_job_data::drop() it's needed to
+ do only disk drop because Event_queue will handle
+ removal from memory queue.
RETURN VALUE
0 OK
@@ -429,7 +421,7 @@ Events::drop_schema_events(THD *thd, char *db)
int ret= 0;
LEX_STRING db_lex= {db, strlen(db)};
- DBUG_ENTER("evex_drop_db_events");
+ DBUG_ENTER("Events::drop_schema_events");
DBUG_PRINT("enter", ("dropping events from %s", db));
pthread_mutex_lock(&LOCK_event_metadata);
@@ -455,24 +447,22 @@ Events::drop_schema_events(THD *thd, char *db)
*/
int
-Events::show_create_event(THD *thd, sp_name *spn)
+Events::show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name)
{
+ CHARSET_INFO *scs= system_charset_info;
int ret;
Event_timed *et= new Event_timed();
- Open_tables_state backup;
DBUG_ENTER("Events::show_create_event");
- DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str));
+ DBUG_PRINT("enter", ("name: %s@%s", dbname.str, name.str));
- thd->reset_n_backup_open_tables_state(&backup);
- ret= db_repository->find_event(thd, spn->m_db, spn->m_name, et);
- thd->restore_backup_open_tables_state(&backup);
+ ret= db_repository->load_named_event(thd, dbname, name, et);
if (!ret)
{
Protocol *protocol= thd->protocol;
- char show_str_buf[768];
- String show_str(show_str_buf, sizeof(show_str_buf), system_charset_info);
+ char show_str_buf[10 * STRING_BUFFER_USUAL_SIZE];
+ String show_str(show_str_buf, sizeof(show_str_buf), scs);
List<Item> field_list;
byte *sql_mode_str;
ulong sql_mode_len=0;
@@ -491,18 +481,19 @@ Events::show_create_event(THD *thd, sp_name *spn)
field_list.push_back(new Item_empty_string("sql_mode", sql_mode_len));
- field_list.push_back(new Item_empty_string("Create Event",
- show_str.length()));
+ field_list.
+ push_back(new Item_empty_string("Create Event", show_str.length()));
+
if (protocol->send_fields(&field_list, Protocol::SEND_NUM_ROWS |
Protocol::SEND_EOF))
goto err;
protocol->prepare_for_resend();
- protocol->store(et->name.str, et->name.length, system_charset_info);
+ protocol->store(et->name.str, et->name.length, scs);
- protocol->store((char*) sql_mode_str, sql_mode_len, system_charset_info);
+ protocol->store((char*) sql_mode_str, sql_mode_len, scs);
- protocol->store(show_str.c_ptr(), show_str.length(), system_charset_info);
+ protocol->store(show_str.c_ptr(), show_str.length(), scs);
ret= protocol->write();
send_eof(thd);
}
@@ -546,7 +537,8 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
DBUG_RETURN(1);
db= thd->lex->select_lex.db;
}
- DBUG_RETURN(get_instance()->db_repository->fill_schema_events(thd, tables, db));
+ DBUG_RETURN(get_instance()->db_repository->
+ fill_schema_events(thd, tables, db));
}
@@ -561,14 +553,12 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
RETURN VALUE
0 OK
- 1 Error
+ 1 Error in case the scheduler can't start
*/
int
Events::init()
{
- int ret= 0;
- Event_db_repository *db_repo;
DBUG_ENTER("Events::init");
event_queue->init_queue(db_repository, scheduler_ng);
scheduler_ng->init_scheduler(event_queue);
@@ -653,7 +643,10 @@ Events::destroy_mutexes()
/*
- Proxy for Event_scheduler::dump_internal_status
+ Dumps the internal status of the scheduler and the memory cache
+ into a table with two columns - Name & Value. Different properties
+ which could be useful for debugging for instance deadlocks are
+ returned.
SYNOPSIS
Events::dump_internal_status()
@@ -733,8 +726,8 @@ Events::stop_execution_of_events()
Events::is_started()
RETURN VALUE
- TRUE Yes
- FALSE No
+ TRUE Yes
+ FALSE No
*/
bool
diff --git a/sql/events.h b/sql/events.h
index f825a75934f..58a1081caa9 100644
--- a/sql/events.h
+++ b/sql/events.h
@@ -81,7 +81,7 @@ public:
uint *rows_affected);
int
- update_event(THD *thd, Event_parse_data *parse_data, sp_name *new_name,
+ update_event(THD *thd, Event_parse_data *parse_data, sp_name *rename_to,
uint *rows_affected);
int
@@ -95,7 +95,7 @@ public:
open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table);
int
- show_create_event(THD *thd, sp_name *spn);
+ show_create_event(THD *thd, LEX_STRING dbname, LEX_STRING name);
/* Needed for both SHOW CREATE EVENT and INFORMATION_SCHEMA */
static int
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index e68d23cfdcd..51030f9d6ba 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -3926,7 +3926,8 @@ end_with_restore_list:
}
if (lex->sql_command == SQLCOM_SHOW_CREATE_EVENT)
- res= Events::get_instance()->show_create_event(thd, lex->spname);
+ res= Events::get_instance()->show_create_event(thd, lex->spname->m_db,
+ lex->spname->m_name);
else
{
uint affected= 1;
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 1cf16a051e3..0dd87fbfac6 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -1447,7 +1447,8 @@ ev_sql_stmt:
LEX *lex=Lex;
// return back to the original memory root ASAP
- lex->sphead->init_strings(YYTHD, lex, NULL);
+ lex->sphead->init_strings(YYTHD, lex,
+ Lex->event_parse_data->identifier);
lex->sphead->restore_thd_mem_root(YYTHD);
lex->sp_chistics.suid= SP_IS_SUID;//always the definer!