summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--mysql-test/r/events.result8
-rw-r--r--mysql-test/r/events_logs_tests.result25
-rw-r--r--mysql-test/t/events.test11
-rw-r--r--mysql-test/t/events_logs_tests.test20
-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
15 files changed, 530 insertions, 567 deletions
diff --git a/mysql-test/r/events.result b/mysql-test/r/events.result
index 2128624786d..05b6ff03786 100644
--- a/mysql-test/r/events.result
+++ b/mysql-test/r/events.result
@@ -111,7 +111,15 @@ a
800219
drop event non_qualif_ev;
drop table non_qualif;
+alter event non_existant rename to non_existant_too;
+ERROR HY000: Unknown event 'non_existant'
set global event_scheduler = 2;
+create event existant on schedule at now() + interval 1 year do select 12;
+alter event non_existant rename to existant;
+ERROR HY000: Event 'existant' already exists
+alter event existant rename to events_test.existant;
+ERROR HY000: Same old and new event name
+drop event existant;
create table t_event3 (a int, b float);
drop event if exists event3;
Warnings:
diff --git a/mysql-test/r/events_logs_tests.result b/mysql-test/r/events_logs_tests.result
index f56ebe3e472..5971dead3c8 100644
--- a/mysql-test/r/events_logs_tests.result
+++ b/mysql-test/r/events_logs_tests.result
@@ -1,5 +1,5 @@
-create database if not exists events_test;
-use events_test;
+CREATE DATABASE IF NOT EXISTS events_test;
+USE events_test;
"We use procedure here because its statements won't be logged into the general log"
"If we had used normal select that are logged in different ways depending on whether"
"the test suite is run in normal mode or with --ps-protocol"
@@ -8,18 +8,21 @@ BEGIN
SELECT user_host, argument FROM mysql.general_log WHERE argument LIKE '%alabala%';
END|
"Check General Query Log"
-SET GLOBAL event_scheduler=2;
-create event log_general on schedule every 1 minute do SELect 'alabala', sleep(1) from dual;
-TRUNCATE mysql.general_log;
-"1 row, the current statement!"
-call select_general_log();
+CALL select_general_log();
user_host argument
+USER_HOST CREATE procedure select_general_log()
+BEGIN
+SELECT user_host, argument FROM mysql.general_log WHERE argument LIKE '%alabala%';
+END
SET GLOBAL event_scheduler=1;
+TRUNCATE mysql.general_log;
+CREATE EVENT log_general ON SCHEDULE EVERY 1 MINUTE DO SELECT 'alabala', SLEEP(1) FROM DUAL;
"Wait the scheduler to start"
-"Should see 3 rows - the 'SELect' is in the middle. The other two are selects from general_log"
-call select_general_log();
+"Should see 2 rows - the 'SELECT' is in the middle. The other two are selects from general_log"
+CALL select_general_log();
user_host argument
-USER_HOST SELect 'alabala', sleep(1) from dual
+USER_HOST CREATE EVENT log_general ON SCHEDULE EVERY 1 MINUTE DO SELECT 'alabala', SLEEP(1) FROM DUAL
+USER_HOST SELECT 'alabala', SLEEP(1) FROM DUAL
DROP PROCEDURE select_general_log;
DROP EVENT log_general;
SET GLOBAL event_scheduler=2;
@@ -90,4 +93,4 @@ TRUNCATE mysql.slow_log;
DROP TABLE slow_event_test;
SET GLOBAL long_query_time =@old_global_long_query_time;
SET SESSION long_query_time =@old_session_long_query_time;
-drop database events_test;
+DROP DATABASE events_test;
diff --git a/mysql-test/t/events.test b/mysql-test/t/events.test
index 34c00a6387a..d45b5906f28 100644
--- a/mysql-test/t/events.test
+++ b/mysql-test/t/events.test
@@ -105,7 +105,18 @@ create event non_qualif_ev on schedule every 10 minute do insert into non_qualif
select * from non_qualif;
drop event non_qualif_ev;
drop table non_qualif;
+
+--error ER_EVENT_DOES_NOT_EXIST
+alter event non_existant rename to non_existant_too;
+
set global event_scheduler = 2;
+create event existant on schedule at now() + interval 1 year do select 12;
+--error ER_EVENT_ALREADY_EXISTS
+alter event non_existant rename to existant;
+--error ER_EVENT_SAME_NAME
+alter event existant rename to events_test.existant;
+drop event existant;
+
create table t_event3 (a int, b float);
drop event if exists event3;
diff --git a/mysql-test/t/events_logs_tests.test b/mysql-test/t/events_logs_tests.test
index 28818083efa..62c2aedf6cc 100644
--- a/mysql-test/t/events_logs_tests.test
+++ b/mysql-test/t/events_logs_tests.test
@@ -1,8 +1,8 @@
# Can't test with embedded server that doesn't support grants
-- source include/not_embedded.inc
-create database if not exists events_test;
-use events_test;
+CREATE DATABASE IF NOT EXISTS events_test;
+USE events_test;
--echo "We use procedure here because its statements won't be logged into the general log"
--echo "If we had used normal select that are logged in different ways depending on whether"
--echo "the test suite is run in normal mode or with --ps-protocol"
@@ -13,18 +13,16 @@ BEGIN
END|
delimiter ;|
--echo "Check General Query Log"
-SET GLOBAL event_scheduler=2;
-create event log_general on schedule every 1 minute do SELect 'alabala', sleep(1) from dual;
-TRUNCATE mysql.general_log;
---echo "1 row, the current statement!"
--replace_column 1 USER_HOST
-call select_general_log();
+CALL select_general_log();
SET GLOBAL event_scheduler=1;
+TRUNCATE mysql.general_log;
+CREATE EVENT log_general ON SCHEDULE EVERY 1 MINUTE DO SELECT 'alabala', SLEEP(1) FROM DUAL;
--echo "Wait the scheduler to start"
---echo "Should see 3 rows - the 'SELect' is in the middle. The other two are selects from general_log"
---sleep 0.7
+--sleep 1.5
+--echo "Should see 2 rows - the 'SELECT' is in the middle. The other two are selects from general_log"
--replace_column 1 USER_HOST
-call select_general_log();
+CALL select_general_log();
DROP PROCEDURE select_general_log;
DROP EVENT log_general;
SET GLOBAL event_scheduler=2;
@@ -102,4 +100,4 @@ DROP TABLE slow_event_test;
SET GLOBAL long_query_time =@old_global_long_query_time;
SET SESSION long_query_time =@old_session_long_query_time;
-drop database events_test;
+DROP DATABASE events_test;
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!