summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorunknown <thek@adventure.(none)>2008-05-09 09:43:02 +0200
committerunknown <thek@adventure.(none)>2008-05-09 09:43:02 +0200
commit3cf9e6eb6b341a763b06febbaa4a0d0ac672408f (patch)
tree09591f37c2d93fb66dd1f852e60e38e672485ccf
parentae7c0deaf99dc7741e42e8333f70694099e2c4af (diff)
downloadmariadb-git-3cf9e6eb6b341a763b06febbaa4a0d0ac672408f.tar.gz
Bug#35997 Event scheduler seems to let the server crash, if it is embedded.
The event scheduler was not designed to work in embedded mode. This patch disables and excludes the event scheduler when the server is compiled for embedded build. libmysqld/Makefile.am: Reduce the amount of event code in an embedded build. mysql-test/t/events_trans.test: Disable test if run in embedded mode. sql/Makefile.am: Introduce definition HAVE_EVENT_SCHEDULER and one new source file. sql/event_data_objects.cc: Refactor Event_parse_data to new file. sql/event_data_objects.h: Refactor Event_parse_data to new file. Move global definitions to new file. sql/event_queue.cc: Move all parsed items to Event_parse_data for easier modularization. sql/events.cc: Move all parsed items to Event_parse_data for easier modularization. sql/mysqld.cc: Disable the event schedular subsystem if the server is compiled in embedded mode. sql/set_var.cc: Disable the event schedular subsystem if the server is compiled in embedded mode. sql/set_var.h: Disable the event schedular subsystem if the server is compiled in embedded mode. sql/sql_db.cc: Disable the event schedular subsystem if the server is compiled in embedded mode. sql/sql_parse.cc: Disable the event schedular subsystem if the server is compiled in embedded mode. sql/sql_show.cc: Disable the event schedular subsystem if the server is compiled in embedded mode. sql/sql_test.cc: Disable the event schedular subsystem if the server is compiled in embedded mode. sql/sql_yacc.yy: Only include event-code needed for parsing to reduce impact on embedded build. Move all constants to Event_parse_data class. mysql-test/r/events_embedded.result: Add test case to make sure the 'event_scheduler' can't be activated in embedded mode. mysql-test/r/is_embedded.require: Add test case to make sure the 'event_scheduler' can't be activated in embedded mode. mysql-test/t/events_embedded.test: Add test case to make sure the 'event_scheduler' can't be activated in embedded mode. sql/event_parse_data.cc: New file. Extracted Event_parse data into a new file. sql/event_parse_data.h: New file. Extracted Event_parse data into a new file.
-rw-r--r--libmysqld/Makefile.am4
-rw-r--r--mysql-test/r/events_embedded.result2
-rw-r--r--mysql-test/r/is_embedded.require2
-rw-r--r--mysql-test/t/events_embedded.test5
-rw-r--r--mysql-test/t/events_trans.test2
-rw-r--r--sql/Makefile.am5
-rw-r--r--sql/event_data_objects.cc559
-rw-r--r--sql/event_data_objects.h99
-rw-r--r--sql/event_parse_data.cc535
-rw-r--r--sql/event_parse_data.h116
-rw-r--r--sql/event_queue.cc18
-rw-r--r--sql/events.cc4
-rw-r--r--sql/mysqld.cc6
-rw-r--r--sql/set_var.cc8
-rw-r--r--sql/set_var.h3
-rw-r--r--sql/sql_db.cc2
-rw-r--r--sql/sql_parse.cc10
-rw-r--r--sql/sql_show.cc18
-rw-r--r--sql/sql_test.cc4
-rw-r--r--sql/sql_yacc.yy13
20 files changed, 745 insertions, 670 deletions
diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am
index c2f342367dd..504980cbd07 100644
--- a/libmysqld/Makefile.am
+++ b/libmysqld/Makefile.am
@@ -73,12 +73,10 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
spatial.cc gstream.cc sql_help.cc tztime.cc sql_cursor.cc \
sp_head.cc sp_pcontext.cc sp.cc sp_cache.cc sp_rcontext.cc \
parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc \
- event_scheduler.cc events.cc event_data_objects.cc \
- event_queue.cc event_db_repository.cc \
rpl_filter.cc sql_partition.cc sql_builtin.cc sql_plugin.cc \
sql_tablespace.cc \
rpl_injector.cc my_user.c partition_info.cc \
- sql_servers.cc
+ sql_servers.cc event_parse_data.cc
libmysqld_int_a_SOURCES= $(libmysqld_sources)
nodist_libmysqld_int_a_SOURCES= $(libmysqlsources) $(sqlsources)
diff --git a/mysql-test/r/events_embedded.result b/mysql-test/r/events_embedded.result
new file mode 100644
index 00000000000..1a02188f2df
--- /dev/null
+++ b/mysql-test/r/events_embedded.result
@@ -0,0 +1,2 @@
+set global event_scheduler=ON;
+ERROR HY000: Unknown system variable 'event_scheduler'
diff --git a/mysql-test/r/is_embedded.require b/mysql-test/r/is_embedded.require
new file mode 100644
index 00000000000..10594809fe7
--- /dev/null
+++ b/mysql-test/r/is_embedded.require
@@ -0,0 +1,2 @@
+have_embedded
+1
diff --git a/mysql-test/t/events_embedded.test b/mysql-test/t/events_embedded.test
new file mode 100644
index 00000000000..9922ea6dfee
--- /dev/null
+++ b/mysql-test/t/events_embedded.test
@@ -0,0 +1,5 @@
+--source include/is_embedded.inc
+
+--error 1193
+set global event_scheduler=ON;
+
diff --git a/mysql-test/t/events_trans.test b/mysql-test/t/events_trans.test
index 562b5a9625f..a94b75bb812 100644
--- a/mysql-test/t/events_trans.test
+++ b/mysql-test/t/events_trans.test
@@ -2,6 +2,8 @@
# Tests that require transactions
#
-- source include/have_innodb.inc
+-- source include/not_embedded.inc
+
--disable_warnings
drop database if exists events_test;
drop database if exists mysqltest_no_such_database;
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 33664b77957..5b5f7aa1c5d 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -73,7 +73,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
parse_file.h sql_view.h sql_trigger.h \
sql_array.h sql_cursor.h events.h scheduler.h \
event_db_repository.h event_queue.h \
- sql_plugin.h authors.h \
+ sql_plugin.h authors.h event_parse_data.h \
event_data_objects.h event_scheduler.h \
sql_partition.h partition_info.h partition_element.h \
contributors.h sql_servers.h
@@ -120,7 +120,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
event_queue.cc event_db_repository.cc events.cc \
sql_plugin.cc sql_binlog.cc \
sql_builtin.cc sql_tablespace.cc partition_info.cc \
- sql_servers.cc
+ sql_servers.cc event_parse_data.cc
nodist_mysqld_SOURCES = mini_client_errors.c pack.c client.c my_time.c my_user.c
@@ -140,6 +140,7 @@ DEFS = -DMYSQL_SERVER \
-DDATADIR="\"$(MYSQLDATAdir)\"" \
-DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
-DPLUGINDIR="\"$(pkgplugindir)\"" \
+ -DHAVE_EVENT_SCHEDULER \
@DEFS@
BUILT_MAINT_SRC = sql_yacc.cc sql_yacc.h
diff --git a/sql/event_data_objects.cc b/sql/event_data_objects.cc
index f4b64ab3012..dd47b8dd916 100644
--- a/sql/event_data_objects.cc
+++ b/sql/event_data_objects.cc
@@ -25,8 +25,6 @@
@{
*/
-#define EVEX_MAX_INTERVAL_VALUE 1000000000L
-
/*************************************************************************/
/**
@@ -188,524 +186,6 @@ Event_queue_element_for_exec::~Event_queue_element_for_exec()
/*
- Returns a new instance
-
- SYNOPSIS
- Event_parse_data::new_instance()
-
- RETURN VALUE
- Address or NULL in case of error
-
- NOTE
- Created on THD's mem_root
-*/
-
-Event_parse_data *
-Event_parse_data::new_instance(THD *thd)
-{
- return new (thd->mem_root) Event_parse_data;
-}
-
-
-/*
- Constructor
-
- SYNOPSIS
- Event_parse_data::Event_parse_data()
-*/
-
-Event_parse_data::Event_parse_data()
- :on_completion(Event_basic::ON_COMPLETION_DROP),
- status(Event_basic::ENABLED),
- do_not_create(FALSE),
- body_changed(FALSE),
- item_starts(NULL), item_ends(NULL), item_execute_at(NULL),
- starts_null(TRUE), ends_null(TRUE), execute_at_null(TRUE),
- item_expression(NULL), expression(0)
-{
- DBUG_ENTER("Event_parse_data::Event_parse_data");
-
- /* Actually in the parser STARTS is always set */
- starts= ends= execute_at= 0;
-
- comment.str= NULL;
- comment.length= 0;
-
- DBUG_VOID_RETURN;
-}
-
-
-/*
- Set a name of the event
-
- SYNOPSIS
- Event_parse_data::init_name()
- thd THD
- spn the name extracted in the parser
-*/
-
-void
-Event_parse_data::init_name(THD *thd, sp_name *spn)
-{
- DBUG_ENTER("Event_parse_data::init_name");
-
- /* We have to copy strings to get them into the right memroot */
- dbname.length= spn->m_db.length;
- dbname.str= thd->strmake(spn->m_db.str, spn->m_db.length);
- name.length= spn->m_name.length;
- name.str= thd->strmake(spn->m_name.str, spn->m_name.length);
-
- if (spn->m_qname.length == 0)
- spn->init_qname(thd);
-
- DBUG_VOID_RETURN;
-}
-
-
-/*
- This function is called on CREATE EVENT or ALTER EVENT. When either
- ENDS or AT is in the past, we are trying to create an event that
- will never be executed. If it has ON COMPLETION NOT PRESERVE
- (default), then it would normally be dropped already, so on CREATE
- EVENT we give a warning, and do not create anyting. On ALTER EVENT
- we give a error, and do not change the event.
-
- If the event has ON COMPLETION PRESERVE, then we see if the event is
- created or altered to the ENABLED (default) state. If so, then we
- give a warning, and change the state to DISABLED.
-
- Otherwise it is a valid event in ON COMPLETION PRESERVE DISABLE
- state.
-*/
-
-void
-Event_parse_data::check_if_in_the_past(THD *thd, my_time_t ltime_utc)
-{
- if (ltime_utc >= (my_time_t) thd->query_start())
- return;
-
- if (on_completion == Event_basic::ON_COMPLETION_DROP)
- {
- switch (thd->lex->sql_command) {
- case SQLCOM_CREATE_EVENT:
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_EVENT_CANNOT_CREATE_IN_THE_PAST,
- ER(ER_EVENT_CANNOT_CREATE_IN_THE_PAST));
- break;
- case SQLCOM_ALTER_EVENT:
- my_error(ER_EVENT_CANNOT_ALTER_IN_THE_PAST, MYF(0));
- break;
- default:
- DBUG_ASSERT(0);
- }
-
- do_not_create= TRUE;
- }
- else if (status == Event_basic::ENABLED)
- {
- status= Event_basic::DISABLED;
- push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
- ER_EVENT_EXEC_TIME_IN_THE_PAST,
- ER(ER_EVENT_EXEC_TIME_IN_THE_PAST));
- }
-}
-
-
-/*
- Sets time for execution for one-time event.
-
- SYNOPSIS
- Event_parse_data::init_execute_at()
- thd Thread
-
- RETURN VALUE
- 0 OK
- ER_WRONG_VALUE Wrong value for execute at (reported)
-*/
-
-int
-Event_parse_data::init_execute_at(THD *thd)
-{
- my_bool not_used;
- MYSQL_TIME ltime;
- my_time_t ltime_utc;
-
- DBUG_ENTER("Event_parse_data::init_execute_at");
-
- if (!item_execute_at)
- DBUG_RETURN(0);
-
- if (item_execute_at->fix_fields(thd, &item_execute_at))
- goto wrong_value;
-
- /* no starts and/or ends in case of execute_at */
- DBUG_PRINT("info", ("starts_null && ends_null should be 1 is %d",
- (starts_null && ends_null)));
- DBUG_ASSERT(starts_null && ends_null);
-
- if ((not_used= item_execute_at->get_date(&ltime, TIME_NO_ZERO_DATE)))
- goto wrong_value;
-
- ltime_utc= TIME_to_timestamp(thd,&ltime,&not_used);
- if (!ltime_utc)
- {
- DBUG_PRINT("error", ("Execute AT after year 2037"));
- goto wrong_value;
- }
-
- check_if_in_the_past(thd, ltime_utc);
-
- execute_at_null= FALSE;
- execute_at= ltime_utc;
- DBUG_RETURN(0);
-
-wrong_value:
- report_bad_value("AT", item_execute_at);
- DBUG_RETURN(ER_WRONG_VALUE);
-}
-
-
-/*
- Sets time for execution of multi-time event.s
-
- SYNOPSIS
- Event_parse_data::init_interval()
- thd Thread
-
- RETURN VALUE
- 0 OK
- EVEX_BAD_PARAMS Interval is not positive or MICROSECOND (reported)
- ER_WRONG_VALUE Wrong value for interval (reported)
-*/
-
-int
-Event_parse_data::init_interval(THD *thd)
-{
- String value;
- INTERVAL interval_tmp;
-
- DBUG_ENTER("Event_parse_data::init_interval");
- if (!item_expression)
- DBUG_RETURN(0);
-
- switch (interval) {
- case INTERVAL_MINUTE_MICROSECOND:
- case INTERVAL_HOUR_MICROSECOND:
- case INTERVAL_DAY_MICROSECOND:
- case INTERVAL_SECOND_MICROSECOND:
- case INTERVAL_MICROSECOND:
- my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND");
- DBUG_RETURN(EVEX_BAD_PARAMS);
- default:
- break;
- }
-
- if (item_expression->fix_fields(thd, &item_expression))
- goto wrong_value;
-
- value.alloc(MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN);
- if (get_interval_value(item_expression, interval, &value, &interval_tmp))
- goto wrong_value;
-
- expression= 0;
-
- switch (interval) {
- case INTERVAL_YEAR:
- expression= interval_tmp.year;
- break;
- case INTERVAL_QUARTER:
- case INTERVAL_MONTH:
- expression= interval_tmp.month;
- break;
- case INTERVAL_WEEK:
- case INTERVAL_DAY:
- expression= interval_tmp.day;
- break;
- case INTERVAL_HOUR:
- expression= interval_tmp.hour;
- break;
- case INTERVAL_MINUTE:
- expression= interval_tmp.minute;
- break;
- case INTERVAL_SECOND:
- expression= interval_tmp.second;
- break;
- case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM
- expression= interval_tmp.year* 12 + interval_tmp.month;
- break;
- case INTERVAL_DAY_HOUR:
- expression= interval_tmp.day* 24 + interval_tmp.hour;
- break;
- case INTERVAL_DAY_MINUTE:
- expression= (interval_tmp.day* 24 + interval_tmp.hour) * 60 +
- interval_tmp.minute;
- break;
- case INTERVAL_HOUR_SECOND: /* day is anyway 0 */
- case INTERVAL_DAY_SECOND:
- /* DAY_SECOND having problems because of leap seconds? */
- expression= ((interval_tmp.day* 24 + interval_tmp.hour) * 60 +
- interval_tmp.minute)*60
- + interval_tmp.second;
- break;
- case INTERVAL_HOUR_MINUTE:
- expression= interval_tmp.hour * 60 + interval_tmp.minute;
- break;
- case INTERVAL_MINUTE_SECOND:
- expression= interval_tmp.minute * 60 + interval_tmp.second;
- break;
- case INTERVAL_LAST:
- DBUG_ASSERT(0);
- default:
- ;/* these are the microsec stuff */
- }
- if (interval_tmp.neg || expression == 0 ||
- expression > EVEX_MAX_INTERVAL_VALUE)
- {
- my_error(ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG, MYF(0));
- DBUG_RETURN(EVEX_BAD_PARAMS);
- }
-
- DBUG_RETURN(0);
-
-wrong_value:
- report_bad_value("INTERVAL", item_expression);
- DBUG_RETURN(ER_WRONG_VALUE);
-}
-
-
-/*
- Sets STARTS.
-
- SYNOPSIS
- Event_parse_data::init_starts()
- expr how much?
-
- NOTES
- Note that activation time is not execution time.
- EVERY 5 MINUTE STARTS "2004-12-12 10:00:00" means that
- the event will be executed every 5 minutes but this will
- start at the date shown above. Expressions are possible :
- DATE_ADD(NOW(), INTERVAL 1 DAY) -- start tommorow at
- same time.
-
- RETURN VALUE
- 0 OK
- ER_WRONG_VALUE Starts before now
-*/
-
-int
-Event_parse_data::init_starts(THD *thd)
-{
- my_bool not_used;
- MYSQL_TIME ltime;
- my_time_t ltime_utc;
-
- DBUG_ENTER("Event_parse_data::init_starts");
- if (!item_starts)
- DBUG_RETURN(0);
-
- if (item_starts->fix_fields(thd, &item_starts))
- goto wrong_value;
-
- if ((not_used= item_starts->get_date(&ltime, TIME_NO_ZERO_DATE)))
- goto wrong_value;
-
- ltime_utc= TIME_to_timestamp(thd, &ltime, &not_used);
- if (!ltime_utc)
- goto wrong_value;
-
- DBUG_PRINT("info",("now: %ld starts: %ld",
- (long) thd->query_start(), (long) ltime_utc));
-
- starts_null= FALSE;
- starts= ltime_utc;
- DBUG_RETURN(0);
-
-wrong_value:
- report_bad_value("STARTS", item_starts);
- DBUG_RETURN(ER_WRONG_VALUE);
-}
-
-
-/*
- Sets ENDS (deactivation time).
-
- SYNOPSIS
- Event_parse_data::init_ends()
- thd THD
-
- NOTES
- Note that activation time is not execution time.
- EVERY 5 MINUTE ENDS "2004-12-12 10:00:00" means that
- the event will be executed every 5 minutes but this will
- end at the date shown above. Expressions are possible :
- DATE_ADD(NOW(), INTERVAL 1 DAY) -- end tommorow at
- same time.
-
- RETURN VALUE
- 0 OK
- EVEX_BAD_PARAMS Error (reported)
-*/
-
-int
-Event_parse_data::init_ends(THD *thd)
-{
- my_bool not_used;
- MYSQL_TIME ltime;
- my_time_t ltime_utc;
-
- DBUG_ENTER("Event_parse_data::init_ends");
- if (!item_ends)
- DBUG_RETURN(0);
-
- if (item_ends->fix_fields(thd, &item_ends))
- goto error_bad_params;
-
- DBUG_PRINT("info", ("convert to TIME"));
- if ((not_used= item_ends->get_date(&ltime, TIME_NO_ZERO_DATE)))
- goto error_bad_params;
-
- ltime_utc= TIME_to_timestamp(thd, &ltime, &not_used);
- if (!ltime_utc)
- goto error_bad_params;
-
- /* Check whether ends is after starts */
- DBUG_PRINT("info", ("ENDS after STARTS?"));
- if (!starts_null && starts >= ltime_utc)
- goto error_bad_params;
-
- check_if_in_the_past(thd, ltime_utc);
-
- ends_null= FALSE;
- ends= ltime_utc;
- DBUG_RETURN(0);
-
-error_bad_params:
- my_error(ER_EVENT_ENDS_BEFORE_STARTS, MYF(0));
- DBUG_RETURN(EVEX_BAD_PARAMS);
-}
-
-
-/*
- Prints an error message about invalid value. Internally used
- during input data verification
-
- SYNOPSIS
- Event_parse_data::report_bad_value()
- item_name The name of the parameter
- bad_item The parameter
-*/
-
-void
-Event_parse_data::report_bad_value(const char *item_name, Item *bad_item)
-{
- char buff[120];
- String str(buff,(uint32) sizeof(buff), system_charset_info);
- String *str2= bad_item->fixed? bad_item->val_str(&str):NULL;
- my_error(ER_WRONG_VALUE, MYF(0), item_name, str2? str2->c_ptr_safe():"NULL");
-}
-
-
-/*
- Checks for validity the data gathered during the parsing phase.
-
- SYNOPSIS
- Event_parse_data::check_parse_data()
- thd Thread
-
- RETURN VALUE
- FALSE OK
- TRUE Error (reported)
-*/
-
-bool
-Event_parse_data::check_parse_data(THD *thd)
-{
- bool ret;
- DBUG_ENTER("Event_parse_data::check_parse_data");
- DBUG_PRINT("info", ("execute_at: 0x%lx expr=0x%lx starts=0x%lx ends=0x%lx",
- (long) item_execute_at, (long) item_expression,
- (long) item_starts, (long) item_ends));
-
- init_name(thd, identifier);
-
- init_definer(thd);
-
- ret= init_execute_at(thd) || init_interval(thd) || init_starts(thd) ||
- init_ends(thd);
- check_originator_id(thd);
- DBUG_RETURN(ret);
-}
-
-
-/*
- Inits definer (definer_user and definer_host) during parsing.
-
- SYNOPSIS
- Event_parse_data::init_definer()
- thd Thread
-*/
-
-void
-Event_parse_data::init_definer(THD *thd)
-{
- DBUG_ENTER("Event_parse_data::init_definer");
-
- DBUG_ASSERT(thd->lex->definer);
-
- const char *definer_user= thd->lex->definer->user.str;
- const char *definer_host= thd->lex->definer->host.str;
- int definer_user_len= thd->lex->definer->user.length;
- int definer_host_len= thd->lex->definer->host.length;
-
- DBUG_PRINT("info",("init definer_user thd->mem_root: 0x%lx "
- "definer_user: 0x%lx", (long) thd->mem_root,
- (long) definer_user));
-
- /* + 1 for @ */
- DBUG_PRINT("info",("init definer as whole"));
- definer.length= definer_user_len + definer_host_len + 1;
- definer.str= (char*) thd->alloc(definer.length + 1);
-
- DBUG_PRINT("info",("copy the user"));
- memcpy(definer.str, definer_user, definer_user_len);
- definer.str[definer_user_len]= '@';
-
- DBUG_PRINT("info",("copy the host"));
- memcpy(definer.str + definer_user_len + 1, definer_host, definer_host_len);
- definer.str[definer.length]= '\0';
- DBUG_PRINT("info",("definer [%s] initted", definer.str));
-
- DBUG_VOID_RETURN;
-}
-
-
-/**
- Set the originator id of the event to the server_id if executing on
- the master or set to the server_id of the master if executing on
- the slave. If executing on slave, also set status to SLAVESIDE_DISABLED.
-
- SYNOPSIS
- Event_parse_data::check_originator_id()
-*/
-void Event_parse_data::check_originator_id(THD *thd)
-{
- /* Disable replicated events on slave. */
- if ((thd->system_thread == SYSTEM_THREAD_SLAVE_SQL) ||
- (thd->system_thread == SYSTEM_THREAD_SLAVE_IO))
- {
- DBUG_PRINT("info", ("Invoked object status set to SLAVESIDE_DISABLED."));
- if ((status == Event_basic::ENABLED) ||
- (status == Event_basic::DISABLED))
- status = Event_basic::SLAVESIDE_DISABLED;
- originator = thd->server_id;
- }
- else
- originator = server_id;
-}
-
-
-/*
Constructor
SYNOPSIS
@@ -799,8 +279,9 @@ Event_basic::load_time_zone(THD *thd, const LEX_STRING tz_name)
Event_queue_element::Event_queue_element():
status_changed(FALSE), last_executed_changed(FALSE),
- on_completion(ON_COMPLETION_DROP), status(ENABLED),
- expression(0), dropped(FALSE), execution_count(0)
+ on_completion(Event_parse_data::ON_COMPLETION_DROP),
+ status(Event_parse_data::ENABLED), expression(0), dropped(FALSE),
+ execution_count(0)
{
DBUG_ENTER("Event_queue_element::Event_queue_element");
@@ -1057,14 +538,14 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table)
switch (ptr[0])
{
case 'E' :
- status = Event_queue_element::ENABLED;
+ status = Event_parse_data::ENABLED;
break;
case 'S' :
- status = Event_queue_element::SLAVESIDE_DISABLED;
+ status = Event_parse_data::SLAVESIDE_DISABLED;
break;
case 'D' :
default:
- status = Event_queue_element::DISABLED;
+ status = Event_parse_data::DISABLED;
break;
}
if ((ptr= get_field(&mem_root, table->field[ET_FIELD_ORIGINATOR])) == NullS)
@@ -1076,8 +557,8 @@ Event_queue_element::load_from_row(THD *thd, TABLE *table)
table->field[ET_FIELD_ON_COMPLETION])) == NullS)
DBUG_RETURN(TRUE);
- on_completion= (ptr[0]=='D'? Event_queue_element::ON_COMPLETION_DROP:
- Event_queue_element::ON_COMPLETION_PRESERVE);
+ on_completion= (ptr[0]=='D'? Event_parse_data::ON_COMPLETION_DROP:
+ Event_parse_data::ON_COMPLETION_PRESERVE);
DBUG_RETURN(FALSE);
}
@@ -1423,7 +904,7 @@ Event_queue_element::compute_next_execution_time()
(long) starts, (long) ends, (long) last_executed,
(long) this));
- if (status != Event_queue_element::ENABLED)
+ if (status != Event_parse_data::ENABLED)
{
DBUG_PRINT("compute_next_execution_time",
("Event %s is DISABLED", name.str));
@@ -1437,10 +918,10 @@ Event_queue_element::compute_next_execution_time()
{
DBUG_PRINT("info",("One-time event %s.%s of was already executed",
dbname.str, name.str));
- dropped= (on_completion == Event_queue_element::ON_COMPLETION_DROP);
+ dropped= (on_completion == Event_parse_data::ON_COMPLETION_DROP);
DBUG_PRINT("info",("One-time event will be dropped: %d.", dropped));
- status= Event_queue_element::DISABLED;
+ status= Event_parse_data::DISABLED;
status_changed= TRUE;
}
goto ret;
@@ -1457,10 +938,10 @@ Event_queue_element::compute_next_execution_time()
/* time_now is after ends. don't execute anymore */
execute_at= 0;
execute_at_null= TRUE;
- if (on_completion == Event_queue_element::ON_COMPLETION_DROP)
+ if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
dropped= TRUE;
DBUG_PRINT("info", ("Dropped: %d", dropped));
- status= Event_queue_element::DISABLED;
+ status= Event_parse_data::DISABLED;
status_changed= TRUE;
goto ret;
@@ -1521,9 +1002,9 @@ Event_queue_element::compute_next_execution_time()
/* Next execution after ends. No more executions */
execute_at= 0;
execute_at_null= TRUE;
- if (on_completion == Event_queue_element::ON_COMPLETION_DROP)
+ if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
dropped= TRUE;
- status= Event_queue_element::DISABLED;
+ status= Event_parse_data::DISABLED;
status_changed= TRUE;
}
else
@@ -1613,9 +1094,9 @@ Event_queue_element::compute_next_execution_time()
DBUG_PRINT("info", ("Next execution after ENDS. Stop executing."));
execute_at= 0;
execute_at_null= TRUE;
- status= Event_queue_element::DISABLED;
+ status= Event_parse_data::DISABLED;
status_changed= TRUE;
- if (on_completion == Event_queue_element::ON_COMPLETION_DROP)
+ if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
dropped= TRUE;
}
else
@@ -1767,14 +1248,14 @@ Event_timed::get_create_event(THD *thd, String *buf)
STRING_WITH_LEN("ON SCHEDULE AT"));
}
- if (on_completion == Event_timed::ON_COMPLETION_DROP)
+ if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
buf->append(STRING_WITH_LEN(" ON COMPLETION NOT PRESERVE "));
else
buf->append(STRING_WITH_LEN(" ON COMPLETION PRESERVE "));
- if (status == Event_timed::ENABLED)
+ if (status == Event_parse_data::ENABLED)
buf->append(STRING_WITH_LEN("ENABLE"));
- else if (status == Event_timed::SLAVESIDE_DISABLED)
+ else if (status == Event_parse_data::SLAVESIDE_DISABLED)
buf->append(STRING_WITH_LEN("DISABLE ON SLAVE"));
else
buf->append(STRING_WITH_LEN("DISABLE"));
diff --git a/sql/event_data_objects.h b/sql/event_data_objects.h
index 7a49d1597d6..e32077b9c97 100644
--- a/sql/event_data_objects.h
+++ b/sql/event_data_objects.h
@@ -22,10 +22,7 @@
@file event_data_objects.h
*/
-#define EVEX_GET_FIELD_FAILED -2
-#define EVEX_BAD_PARAMS -5
-#define EVEX_MICROSECOND_UNSUP -6
-
+#include "event_parse_data.h"
class Event_queue_element_for_exec
{
@@ -54,23 +51,6 @@ protected:
MEM_ROOT mem_root;
public:
- /*
- ENABLED = feature can function normally (is turned on)
- SLAVESIDE_DISABLED = feature is turned off on slave
- DISABLED = feature is turned off
- */
- enum enum_status
- {
- ENABLED = 1,
- DISABLED,
- SLAVESIDE_DISABLED
- };
-
- enum enum_on_completion
- {
- ON_COMPLETION_DROP = 1,
- ON_COMPLETION_PRESERVE
- };
LEX_STRING dbname;
LEX_STRING name;
@@ -201,83 +181,6 @@ private:
};
-class Event_parse_data : public Sql_alloc
-{
-public:
-
- int on_completion;
- int status;
- longlong originator;
- /*
- do_not_create will be set if STARTS time is in the past and
- on_completion == ON_COMPLETION_DROP.
- */
- bool do_not_create;
-
- bool body_changed;
-
- LEX_STRING dbname;
- LEX_STRING name;
- LEX_STRING definer;// combination of user and host
- LEX_STRING comment;
-
- Item* item_starts;
- Item* item_ends;
- Item* item_execute_at;
-
- my_time_t starts;
- my_time_t ends;
- my_time_t execute_at;
- my_bool starts_null;
- my_bool ends_null;
- my_bool execute_at_null;
-
- sp_name *identifier;
- Item* item_expression;
- longlong expression;
- interval_type interval;
-
- static Event_parse_data *
- new_instance(THD *thd);
-
- bool
- check_parse_data(THD *thd);
-
-private:
-
- void
- init_definer(THD *thd);
-
- void
- init_name(THD *thd, sp_name *spn);
-
- int
- init_execute_at(THD *thd);
-
- int
- init_interval(THD *thd);
-
- int
- init_starts(THD *thd);
-
- int
- init_ends(THD *thd);
-
- Event_parse_data();
- ~Event_parse_data();
-
- void
- report_bad_value(const char *item_name, Item *bad_item);
-
- void
- check_if_in_the_past(THD *thd, my_time_t ltime_utc);
-
- Event_parse_data(const Event_parse_data &); /* Prevent use of these */
- void check_originator_id(THD *thd);
- void operator=(Event_parse_data &);
-};
-
-
/* Compares only the schema part of the identifier */
bool
event_basic_db_equal(LEX_STRING db, Event_basic *et);
diff --git a/sql/event_parse_data.cc b/sql/event_parse_data.cc
new file mode 100644
index 00000000000..e87e4593f8f
--- /dev/null
+++ b/sql/event_parse_data.cc
@@ -0,0 +1,535 @@
+/* Copyright (C) 2000-2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include "mysql_priv.h"
+#include "sp_head.h"
+#include "event_parse_data.h"
+
+/*
+ Returns a new instance
+
+ SYNOPSIS
+ Event_parse_data::new_instance()
+
+ RETURN VALUE
+ Address or NULL in case of error
+
+ NOTE
+ Created on THD's mem_root
+*/
+
+Event_parse_data *
+Event_parse_data::new_instance(THD *thd)
+{
+ return new (thd->mem_root) Event_parse_data;
+}
+
+
+/*
+ Constructor
+
+ SYNOPSIS
+ Event_parse_data::Event_parse_data()
+*/
+
+Event_parse_data::Event_parse_data()
+ :on_completion(Event_parse_data::ON_COMPLETION_DROP),
+ status(Event_parse_data::ENABLED),
+ do_not_create(FALSE),
+ body_changed(FALSE),
+ item_starts(NULL), item_ends(NULL), item_execute_at(NULL),
+ starts_null(TRUE), ends_null(TRUE), execute_at_null(TRUE),
+ item_expression(NULL), expression(0)
+{
+ DBUG_ENTER("Event_parse_data::Event_parse_data");
+
+ /* Actually in the parser STARTS is always set */
+ starts= ends= execute_at= 0;
+
+ comment.str= NULL;
+ comment.length= 0;
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ Set a name of the event
+
+ SYNOPSIS
+ Event_parse_data::init_name()
+ thd THD
+ spn the name extracted in the parser
+*/
+
+void
+Event_parse_data::init_name(THD *thd, sp_name *spn)
+{
+ DBUG_ENTER("Event_parse_data::init_name");
+
+ /* We have to copy strings to get them into the right memroot */
+ dbname.length= spn->m_db.length;
+ dbname.str= thd->strmake(spn->m_db.str, spn->m_db.length);
+ name.length= spn->m_name.length;
+ name.str= thd->strmake(spn->m_name.str, spn->m_name.length);
+
+ if (spn->m_qname.length == 0)
+ spn->init_qname(thd);
+
+ DBUG_VOID_RETURN;
+}
+
+
+/*
+ This function is called on CREATE EVENT or ALTER EVENT. When either
+ ENDS or AT is in the past, we are trying to create an event that
+ will never be executed. If it has ON COMPLETION NOT PRESERVE
+ (default), then it would normally be dropped already, so on CREATE
+ EVENT we give a warning, and do not create anyting. On ALTER EVENT
+ we give a error, and do not change the event.
+
+ If the event has ON COMPLETION PRESERVE, then we see if the event is
+ created or altered to the ENABLED (default) state. If so, then we
+ give a warning, and change the state to DISABLED.
+
+ Otherwise it is a valid event in ON COMPLETION PRESERVE DISABLE
+ state.
+*/
+
+void
+Event_parse_data::check_if_in_the_past(THD *thd, my_time_t ltime_utc)
+{
+ if (ltime_utc >= (my_time_t) thd->query_start())
+ return;
+
+ if (on_completion == Event_parse_data::ON_COMPLETION_DROP)
+ {
+ switch (thd->lex->sql_command) {
+ case SQLCOM_CREATE_EVENT:
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_EVENT_CANNOT_CREATE_IN_THE_PAST,
+ ER(ER_EVENT_CANNOT_CREATE_IN_THE_PAST));
+ break;
+ case SQLCOM_ALTER_EVENT:
+ my_error(ER_EVENT_CANNOT_ALTER_IN_THE_PAST, MYF(0));
+ break;
+ default:
+ DBUG_ASSERT(0);
+ }
+
+ do_not_create= TRUE;
+ }
+ else if (status == Event_parse_data::ENABLED)
+ {
+ status= Event_parse_data::DISABLED;
+ push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+ ER_EVENT_EXEC_TIME_IN_THE_PAST,
+ ER(ER_EVENT_EXEC_TIME_IN_THE_PAST));
+ }
+}
+
+
+/*
+ Sets time for execution for one-time event.
+
+ SYNOPSIS
+ Event_parse_data::init_execute_at()
+ thd Thread
+
+ RETURN VALUE
+ 0 OK
+ ER_WRONG_VALUE Wrong value for execute at (reported)
+*/
+
+int
+Event_parse_data::init_execute_at(THD *thd)
+{
+ my_bool not_used;
+ MYSQL_TIME ltime;
+ my_time_t ltime_utc;
+
+ DBUG_ENTER("Event_parse_data::init_execute_at");
+
+ if (!item_execute_at)
+ DBUG_RETURN(0);
+
+ if (item_execute_at->fix_fields(thd, &item_execute_at))
+ goto wrong_value;
+
+ /* no starts and/or ends in case of execute_at */
+ DBUG_PRINT("info", ("starts_null && ends_null should be 1 is %d",
+ (starts_null && ends_null)));
+ DBUG_ASSERT(starts_null && ends_null);
+
+ if ((not_used= item_execute_at->get_date(&ltime, TIME_NO_ZERO_DATE)))
+ goto wrong_value;
+
+ ltime_utc= TIME_to_timestamp(thd,&ltime,&not_used);
+ if (!ltime_utc)
+ {
+ DBUG_PRINT("error", ("Execute AT after year 2037"));
+ goto wrong_value;
+ }
+
+ check_if_in_the_past(thd, ltime_utc);
+
+ execute_at_null= FALSE;
+ execute_at= ltime_utc;
+ DBUG_RETURN(0);
+
+wrong_value:
+ report_bad_value("AT", item_execute_at);
+ DBUG_RETURN(ER_WRONG_VALUE);
+}
+
+
+/*
+ Sets time for execution of multi-time event.s
+
+ SYNOPSIS
+ Event_parse_data::init_interval()
+ thd Thread
+
+ RETURN VALUE
+ 0 OK
+ EVEX_BAD_PARAMS Interval is not positive or MICROSECOND (reported)
+ ER_WRONG_VALUE Wrong value for interval (reported)
+*/
+
+int
+Event_parse_data::init_interval(THD *thd)
+{
+ String value;
+ INTERVAL interval_tmp;
+
+ DBUG_ENTER("Event_parse_data::init_interval");
+ if (!item_expression)
+ DBUG_RETURN(0);
+
+ switch (interval) {
+ case INTERVAL_MINUTE_MICROSECOND:
+ case INTERVAL_HOUR_MICROSECOND:
+ case INTERVAL_DAY_MICROSECOND:
+ case INTERVAL_SECOND_MICROSECOND:
+ case INTERVAL_MICROSECOND:
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0), "MICROSECOND");
+ DBUG_RETURN(EVEX_BAD_PARAMS);
+ default:
+ break;
+ }
+
+ if (item_expression->fix_fields(thd, &item_expression))
+ goto wrong_value;
+
+ value.alloc(MAX_DATETIME_FULL_WIDTH*MY_CHARSET_BIN_MB_MAXLEN);
+ if (get_interval_value(item_expression, interval, &value, &interval_tmp))
+ goto wrong_value;
+
+ expression= 0;
+
+ switch (interval) {
+ case INTERVAL_YEAR:
+ expression= interval_tmp.year;
+ break;
+ case INTERVAL_QUARTER:
+ case INTERVAL_MONTH:
+ expression= interval_tmp.month;
+ break;
+ case INTERVAL_WEEK:
+ case INTERVAL_DAY:
+ expression= interval_tmp.day;
+ break;
+ case INTERVAL_HOUR:
+ expression= interval_tmp.hour;
+ break;
+ case INTERVAL_MINUTE:
+ expression= interval_tmp.minute;
+ break;
+ case INTERVAL_SECOND:
+ expression= interval_tmp.second;
+ break;
+ case INTERVAL_YEAR_MONTH: // Allow YEAR-MONTH YYYYYMM
+ expression= interval_tmp.year* 12 + interval_tmp.month;
+ break;
+ case INTERVAL_DAY_HOUR:
+ expression= interval_tmp.day* 24 + interval_tmp.hour;
+ break;
+ case INTERVAL_DAY_MINUTE:
+ expression= (interval_tmp.day* 24 + interval_tmp.hour) * 60 +
+ interval_tmp.minute;
+ break;
+ case INTERVAL_HOUR_SECOND: /* day is anyway 0 */
+ case INTERVAL_DAY_SECOND:
+ /* DAY_SECOND having problems because of leap seconds? */
+ expression= ((interval_tmp.day* 24 + interval_tmp.hour) * 60 +
+ interval_tmp.minute)*60
+ + interval_tmp.second;
+ break;
+ case INTERVAL_HOUR_MINUTE:
+ expression= interval_tmp.hour * 60 + interval_tmp.minute;
+ break;
+ case INTERVAL_MINUTE_SECOND:
+ expression= interval_tmp.minute * 60 + interval_tmp.second;
+ break;
+ case INTERVAL_LAST:
+ DBUG_ASSERT(0);
+ default:
+ ;/* these are the microsec stuff */
+ }
+ if (interval_tmp.neg || expression == 0 ||
+ expression > EVEX_MAX_INTERVAL_VALUE)
+ {
+ my_error(ER_EVENT_INTERVAL_NOT_POSITIVE_OR_TOO_BIG, MYF(0));
+ DBUG_RETURN(EVEX_BAD_PARAMS);
+ }
+
+ DBUG_RETURN(0);
+
+wrong_value:
+ report_bad_value("INTERVAL", item_expression);
+ DBUG_RETURN(ER_WRONG_VALUE);
+}
+
+
+/*
+ Sets STARTS.
+
+ SYNOPSIS
+ Event_parse_data::init_starts()
+ expr how much?
+
+ NOTES
+ Note that activation time is not execution time.
+ EVERY 5 MINUTE STARTS "2004-12-12 10:00:00" means that
+ the event will be executed every 5 minutes but this will
+ start at the date shown above. Expressions are possible :
+ DATE_ADD(NOW(), INTERVAL 1 DAY) -- start tommorow at
+ same time.
+
+ RETURN VALUE
+ 0 OK
+ ER_WRONG_VALUE Starts before now
+*/
+
+int
+Event_parse_data::init_starts(THD *thd)
+{
+ my_bool not_used;
+ MYSQL_TIME ltime;
+ my_time_t ltime_utc;
+
+ DBUG_ENTER("Event_parse_data::init_starts");
+ if (!item_starts)
+ DBUG_RETURN(0);
+
+ if (item_starts->fix_fields(thd, &item_starts))
+ goto wrong_value;
+
+ if ((not_used= item_starts->get_date(&ltime, TIME_NO_ZERO_DATE)))
+ goto wrong_value;
+
+ ltime_utc= TIME_to_timestamp(thd, &ltime, &not_used);
+ if (!ltime_utc)
+ goto wrong_value;
+
+ DBUG_PRINT("info",("now: %ld starts: %ld",
+ (long) thd->query_start(), (long) ltime_utc));
+
+ starts_null= FALSE;
+ starts= ltime_utc;
+ DBUG_RETURN(0);
+
+wrong_value:
+ report_bad_value("STARTS", item_starts);
+ DBUG_RETURN(ER_WRONG_VALUE);
+}
+
+
+/*
+ Sets ENDS (deactivation time).
+
+ SYNOPSIS
+ Event_parse_data::init_ends()
+ thd THD
+
+ NOTES
+ Note that activation time is not execution time.
+ EVERY 5 MINUTE ENDS "2004-12-12 10:00:00" means that
+ the event will be executed every 5 minutes but this will
+ end at the date shown above. Expressions are possible :
+ DATE_ADD(NOW(), INTERVAL 1 DAY) -- end tommorow at
+ same time.
+
+ RETURN VALUE
+ 0 OK
+ EVEX_BAD_PARAMS Error (reported)
+*/
+
+int
+Event_parse_data::init_ends(THD *thd)
+{
+ my_bool not_used;
+ MYSQL_TIME ltime;
+ my_time_t ltime_utc;
+
+ DBUG_ENTER("Event_parse_data::init_ends");
+ if (!item_ends)
+ DBUG_RETURN(0);
+
+ if (item_ends->fix_fields(thd, &item_ends))
+ goto error_bad_params;
+
+ DBUG_PRINT("info", ("convert to TIME"));
+ if ((not_used= item_ends->get_date(&ltime, TIME_NO_ZERO_DATE)))
+ goto error_bad_params;
+
+ ltime_utc= TIME_to_timestamp(thd, &ltime, &not_used);
+ if (!ltime_utc)
+ goto error_bad_params;
+
+ /* Check whether ends is after starts */
+ DBUG_PRINT("info", ("ENDS after STARTS?"));
+ if (!starts_null && starts >= ltime_utc)
+ goto error_bad_params;
+
+ check_if_in_the_past(thd, ltime_utc);
+
+ ends_null= FALSE;
+ ends= ltime_utc;
+ DBUG_RETURN(0);
+
+error_bad_params:
+ my_error(ER_EVENT_ENDS_BEFORE_STARTS, MYF(0));
+ DBUG_RETURN(EVEX_BAD_PARAMS);
+}
+
+
+/*
+ Prints an error message about invalid value. Internally used
+ during input data verification
+
+ SYNOPSIS
+ Event_parse_data::report_bad_value()
+ item_name The name of the parameter
+ bad_item The parameter
+*/
+
+void
+Event_parse_data::report_bad_value(const char *item_name, Item *bad_item)
+{
+ char buff[120];
+ String str(buff,(uint32) sizeof(buff), system_charset_info);
+ String *str2= bad_item->fixed? bad_item->val_str(&str):NULL;
+ my_error(ER_WRONG_VALUE, MYF(0), item_name, str2? str2->c_ptr_safe():"NULL");
+}
+
+
+/*
+ Checks for validity the data gathered during the parsing phase.
+
+ SYNOPSIS
+ Event_parse_data::check_parse_data()
+ thd Thread
+
+ RETURN VALUE
+ FALSE OK
+ TRUE Error (reported)
+*/
+
+bool
+Event_parse_data::check_parse_data(THD *thd)
+{
+ bool ret;
+ DBUG_ENTER("Event_parse_data::check_parse_data");
+ DBUG_PRINT("info", ("execute_at: 0x%lx expr=0x%lx starts=0x%lx ends=0x%lx",
+ (long) item_execute_at, (long) item_expression,
+ (long) item_starts, (long) item_ends));
+
+ init_name(thd, identifier);
+
+ init_definer(thd);
+
+ ret= init_execute_at(thd) || init_interval(thd) || init_starts(thd) ||
+ init_ends(thd);
+ check_originator_id(thd);
+ DBUG_RETURN(ret);
+}
+
+
+/*
+ Inits definer (definer_user and definer_host) during parsing.
+
+ SYNOPSIS
+ Event_parse_data::init_definer()
+ thd Thread
+*/
+
+void
+Event_parse_data::init_definer(THD *thd)
+{
+ DBUG_ENTER("Event_parse_data::init_definer");
+
+ DBUG_ASSERT(thd->lex->definer);
+
+ const char *definer_user= thd->lex->definer->user.str;
+ const char *definer_host= thd->lex->definer->host.str;
+ int definer_user_len= thd->lex->definer->user.length;
+ int definer_host_len= thd->lex->definer->host.length;
+
+ DBUG_PRINT("info",("init definer_user thd->mem_root: 0x%lx "
+ "definer_user: 0x%lx", (long) thd->mem_root,
+ (long) definer_user));
+
+ /* + 1 for @ */
+ DBUG_PRINT("info",("init definer as whole"));
+ definer.length= definer_user_len + definer_host_len + 1;
+ definer.str= (char*) thd->alloc(definer.length + 1);
+
+ DBUG_PRINT("info",("copy the user"));
+ memcpy(definer.str, definer_user, definer_user_len);
+ definer.str[definer_user_len]= '@';
+
+ DBUG_PRINT("info",("copy the host"));
+ memcpy(definer.str + definer_user_len + 1, definer_host, definer_host_len);
+ definer.str[definer.length]= '\0';
+ DBUG_PRINT("info",("definer [%s] initted", definer.str));
+
+ DBUG_VOID_RETURN;
+}
+
+
+/**
+ Set the originator id of the event to the server_id if executing on
+ the master or set to the server_id of the master if executing on
+ the slave. If executing on slave, also set status to SLAVESIDE_DISABLED.
+
+ SYNOPSIS
+ Event_parse_data::check_originator_id()
+*/
+void Event_parse_data::check_originator_id(THD *thd)
+{
+ /* Disable replicated events on slave. */
+ if ((thd->system_thread == SYSTEM_THREAD_SLAVE_SQL) ||
+ (thd->system_thread == SYSTEM_THREAD_SLAVE_IO))
+ {
+ DBUG_PRINT("info", ("Invoked object status set to SLAVESIDE_DISABLED."));
+ if ((status == Event_parse_data::ENABLED) ||
+ (status == Event_parse_data::DISABLED))
+ status = Event_parse_data::SLAVESIDE_DISABLED;
+ originator = thd->server_id;
+ }
+ else
+ originator = server_id;
+}
diff --git a/sql/event_parse_data.h b/sql/event_parse_data.h
new file mode 100644
index 00000000000..221bf92664f
--- /dev/null
+++ b/sql/event_parse_data.h
@@ -0,0 +1,116 @@
+/* Copyright (C) 2000-2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; version 2 of the License.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#ifndef _EVENT_PARSE_DATA_H_
+#define _EVENT_PARSE_DATA_H_
+
+#define EVEX_GET_FIELD_FAILED -2
+#define EVEX_BAD_PARAMS -5
+#define EVEX_MICROSECOND_UNSUP -6
+#define EVEX_MAX_INTERVAL_VALUE 1000000000L
+
+class Event_parse_data : public Sql_alloc
+{
+public:
+ /*
+ ENABLED = feature can function normally (is turned on)
+ SLAVESIDE_DISABLED = feature is turned off on slave
+ DISABLED = feature is turned off
+ */
+ enum enum_status
+ {
+ ENABLED = 1,
+ DISABLED,
+ SLAVESIDE_DISABLED
+ };
+
+ enum enum_on_completion
+ {
+ ON_COMPLETION_DROP = 1,
+ ON_COMPLETION_PRESERVE
+ };
+
+ int on_completion;
+ int status;
+ longlong originator;
+ /*
+ do_not_create will be set if STARTS time is in the past and
+ on_completion == ON_COMPLETION_DROP.
+ */
+ bool do_not_create;
+
+ bool body_changed;
+
+ LEX_STRING dbname;
+ LEX_STRING name;
+ LEX_STRING definer;// combination of user and host
+ LEX_STRING comment;
+
+ Item* item_starts;
+ Item* item_ends;
+ Item* item_execute_at;
+
+ my_time_t starts;
+ my_time_t ends;
+ my_time_t execute_at;
+ my_bool starts_null;
+ my_bool ends_null;
+ my_bool execute_at_null;
+
+ sp_name *identifier;
+ Item* item_expression;
+ longlong expression;
+ interval_type interval;
+
+ static Event_parse_data *
+ new_instance(THD *thd);
+
+ bool
+ check_parse_data(THD *thd);
+
+private:
+
+ void
+ init_definer(THD *thd);
+
+ void
+ init_name(THD *thd, sp_name *spn);
+
+ int
+ init_execute_at(THD *thd);
+
+ int
+ init_interval(THD *thd);
+
+ int
+ init_starts(THD *thd);
+
+ int
+ init_ends(THD *thd);
+
+ Event_parse_data();
+ ~Event_parse_data();
+
+ void
+ report_bad_value(const char *item_name, Item *bad_item);
+
+ void
+ check_if_in_the_past(THD *thd, my_time_t ltime_utc);
+
+ Event_parse_data(const Event_parse_data &); /* Prevent use of these */
+ void check_originator_id(THD *thd);
+ void operator=(Event_parse_data &);
+};
+#endif
diff --git a/sql/event_queue.cc b/sql/event_queue.cc
index 719a837cbfb..04d4f858b43 100644
--- a/sql/event_queue.cc
+++ b/sql/event_queue.cc
@@ -65,10 +65,10 @@ int event_queue_element_compare_q(void *vptr, uchar* a, uchar *b)
my_time_t lhs = left->execute_at;
my_time_t rhs = right->execute_at;
- if (left->status == Event_queue_element::DISABLED)
- return right->status != Event_queue_element::DISABLED;
+ if (left->status == Event_parse_data::DISABLED)
+ return right->status != Event_parse_data::DISABLED;
- if (right->status == Event_queue_element::DISABLED)
+ if (right->status == Event_parse_data::DISABLED)
return 1;
return (lhs < rhs ? -1 : (lhs > rhs ? 1 : 0));
@@ -198,7 +198,7 @@ Event_queue::create_event(THD *thd, Event_queue_element *new_element,
/* Will do nothing if the event is disabled */
new_element->compute_next_execution_time();
- if (new_element->status != Event_queue_element::ENABLED)
+ if (new_element->status != Event_parse_data::ENABLED)
{
delete new_element;
*created= FALSE;
@@ -236,8 +236,8 @@ Event_queue::update_event(THD *thd, LEX_STRING dbname, LEX_STRING name,
DBUG_ENTER("Event_queue::update_event");
DBUG_PRINT("enter", ("thd: 0x%lx et=[%s.%s]", (long) thd, dbname.str, name.str));
- if ((new_element->status == Event_queue_element::DISABLED) ||
- (new_element->status == Event_queue_element::SLAVESIDE_DISABLED))
+ if ((new_element->status == Event_parse_data::DISABLED) ||
+ (new_element->status == Event_parse_data::SLAVESIDE_DISABLED))
{
DBUG_PRINT("info", ("The event is disabled."));
/*
@@ -452,7 +452,7 @@ Event_queue::recalculate_activation_times(THD *thd)
for (i= queue.elements; i > 0; i--)
{
Event_queue_element *element = (Event_queue_element*)queue_element(&queue, i - 1);
- if (element->status != Event_queue_element::DISABLED)
+ if (element->status != Event_parse_data::DISABLED)
break;
/*
This won't cause queue re-order, because we remove
@@ -615,14 +615,14 @@ Event_queue::get_top_for_execution_if_time(THD *thd,
DBUG_PRINT("info", ("Ready for execution"));
top->mark_last_executed(thd);
if (top->compute_next_execution_time())
- top->status= Event_queue_element::DISABLED;
+ top->status= Event_parse_data::DISABLED;
DBUG_PRINT("info", ("event %s status is %d", top->name.str, top->status));
top->execution_count++;
(*event_name)->dropped= top->dropped;
top->update_timing_fields(thd);
- if (top->status == Event_queue_element::DISABLED)
+ if (top->status == Event_parse_data::DISABLED)
{
DBUG_PRINT("info", ("removing from the queue"));
sql_print_information("Event Scheduler: Last execution of %s.%s. %s",
diff --git a/sql/events.cc b/sql/events.cc
index 4225ca055de..a98c1c90298 100644
--- a/sql/events.cc
+++ b/sql/events.cc
@@ -861,6 +861,7 @@ Events::fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */)
bool
Events::init(my_bool opt_noacl)
{
+
THD *thd;
bool res= FALSE;
@@ -954,7 +955,6 @@ end:
DBUG_RETURN(res);
}
-
/*
Cleans up scheduler's resources. Called at server shutdown.
@@ -1170,7 +1170,7 @@ Events::load_events_from_db(THD *thd)
goto end;
}
drop_on_completion= (et->on_completion ==
- Event_queue_element::ON_COMPLETION_DROP);
+ Event_parse_data::ON_COMPLETION_DROP);
if (event_queue->create_event(thd, et, &created))
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index f619899f3b1..0c1ad3ffc69 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -3498,7 +3498,9 @@ static int init_thread_environment()
(void) pthread_mutex_init(&LOCK_server_started, MY_MUTEX_INIT_FAST);
(void) pthread_cond_init(&COND_server_started,NULL);
sp_cache_init();
+#ifdef HAVE_EVENT_SCHEDULER
Events::init_mutexes();
+#endif
/* Parameter for threads created for connections */
(void) pthread_attr_init(&connection_attrib);
(void) pthread_attr_setdetachstate(&connection_attrib,
@@ -7831,8 +7833,12 @@ mysqld_get_one_option(int optid,
}
#endif
case OPT_EVENT_SCHEDULER:
+#ifndef HAVE_EVENT_SCHEDULER
+ sql_perror("Event scheduler is not supported in embedded build.");
+#else
if (Events::set_opt_event_scheduler(argument))
exit(1);
+#endif
break;
case (int) OPT_SKIP_NEW:
opt_specialflag|= SPECIAL_NO_NEW_FUNC;
diff --git a/sql/set_var.cc b/sql/set_var.cc
index b4b81ba2fbe..fd81dc1a867 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -241,7 +241,10 @@ static sys_var_long_ptr sys_delayed_insert_timeout(&vars, "delayed_insert_timeou
static sys_var_long_ptr sys_delayed_queue_size(&vars, "delayed_queue_size",
&delayed_queue_size);
+#ifdef HAVE_EVENT_SCHEDULER
static sys_var_event_scheduler sys_event_scheduler(&vars, "event_scheduler");
+#endif
+
static sys_var_long_ptr sys_expire_logs_days(&vars, "expire_logs_days",
&expire_logs_days);
static sys_var_bool_ptr sys_flush(&vars, "flush", &myisam_flush);
@@ -4026,13 +4029,12 @@ uchar *sys_var_thd_dbug::value_ptr(THD *thd, enum_var_type type, LEX_STRING *b)
return (uchar*) thd->strdup(buf);
}
-
+#ifdef HAVE_EVENT_SCHEDULER
bool sys_var_event_scheduler::check(THD *thd, set_var *var)
{
return check_enum(thd, var, &Events::var_typelib);
}
-
/*
The update method of the global variable event_scheduler.
If event_scheduler is switched from 0 to 1 then the scheduler main
@@ -4071,7 +4073,7 @@ uchar *sys_var_event_scheduler::value_ptr(THD *thd, enum_var_type type,
{
return (uchar *) Events::get_opt_event_scheduler_str();
}
-
+#endif
/****************************************************************************
Used templates
diff --git a/sql/set_var.h b/sql/set_var.h
index b33a3a968bb..290d1bf0eb1 100644
--- a/sql/set_var.h
+++ b/sql/set_var.h
@@ -1085,7 +1085,7 @@ public:
virtual void set_default(THD *thd, enum_var_type type);
};
-
+#ifdef HAVE_EVENT_SCHEDULER
class sys_var_event_scheduler :public sys_var_long_ptr
{
/* We need a derived class only to have a warn_deprecated() */
@@ -1101,6 +1101,7 @@ public:
return type != STRING_RESULT && type != INT_RESULT;
}
};
+#endif
extern void fix_binlog_format_after_update(THD *thd, enum_var_type type);
diff --git a/sql/sql_db.cc b/sql/sql_db.cc
index 2c7e0e82b3c..bb55f5f7a4f 100644
--- a/sql/sql_db.cc
+++ b/sql/sql_db.cc
@@ -922,7 +922,9 @@ bool mysql_rm_db(THD *thd,char *db,bool if_exists, bool silent)
ha_drop_database(path);
query_cache_invalidate1(db);
(void) sp_drop_db_routines(thd, db); /* @todo Do not ignore errors */
+#ifdef HAVE_EVENT_SCHEDULER
Events::drop_schema_events(thd, db);
+#endif
error = 0;
}
}
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index f2e8d713371..ddcec92a0d3 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -1998,7 +1998,12 @@ mysql_execute_command(THD *thd)
DBUG_ASSERT(thd->transaction.stmt.modified_non_trans_table == FALSE);
switch (lex->sql_command) {
+
case SQLCOM_SHOW_EVENTS:
+#ifndef HAVE_EVENT_SCHEDULER
+ my_error(ER_NOT_SUPPORTED_YET, MYF(0), "embedded server");
+ break;
+#endif
case SQLCOM_SHOW_STATUS_PROC:
case SQLCOM_SHOW_STATUS_FUNC:
res= execute_sqlcom_select(thd, all_tables);
@@ -3483,6 +3488,7 @@ end_with_restore_list:
}
case SQLCOM_CREATE_EVENT:
case SQLCOM_ALTER_EVENT:
+ #ifdef HAVE_EVENT_SCHEDULER
do
{
DBUG_ASSERT(lex->event_parse_data);
@@ -3536,6 +3542,10 @@ end_with_restore_list:
lex->drop_if_exists)))
my_ok(thd);
break;
+#else
+ my_error(ER_NOT_SUPPORTED_YET,MYF(0),"embedded server");
+ break;
+#endif
case SQLCOM_CREATE_FUNCTION: // UDF function
{
if (check_access(thd,INSERT_ACL,"mysql",0,1,0,0))
diff --git a/sql/sql_show.cc b/sql/sql_show.cc
index b005615ce7c..57280f39199 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -25,8 +25,10 @@
#include "sql_trigger.h"
#include "authors.h"
#include "contributors.h"
+#ifdef HAVE_EVENT_SCHEDULER
#include "events.h"
#include "event_data_objects.h"
+#endif
#include <my_dir.h>
#define STR_OR_NIL(S) ((S) ? (S) : "<nil>")
@@ -287,7 +289,9 @@ static struct show_privileges_st sys_privileges[]=
{"Create user", "Server Admin", "To create new users"},
{"Delete", "Tables", "To delete existing rows"},
{"Drop", "Databases,Tables", "To drop databases, tables, and views"},
+#ifdef HAVE_EVENT_SCHEDULER
{"Event","Server Admin","To create, alter, drop and execute events"},
+#endif
{"Execute", "Functions,Procedures", "To execute stored routines"},
{"File", "File access on server", "To read and write files on the server"},
{"Grant option", "Databases,Tables,Functions,Procedures", "To give to other users those privileges you possess"},
@@ -4959,7 +4963,7 @@ static interval_type get_real_interval_type(interval_type i_type)
#endif
-
+#ifdef HAVE_EVENT_SCHEDULER
/*
Loads an event from mysql.event and copies it's data to a row of
I_S.EVENTS
@@ -5079,14 +5083,14 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
switch (et.status)
{
- case Event_timed::ENABLED:
+ case Event_parse_data::ENABLED:
sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("ENABLED"), scs);
break;
- case Event_timed::SLAVESIDE_DISABLED:
+ case Event_parse_data::SLAVESIDE_DISABLED:
sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("SLAVESIDE_DISABLED"),
scs);
break;
- case Event_timed::DISABLED:
+ case Event_parse_data::DISABLED:
sch_table->field[ISE_STATUS]->store(STRING_WITH_LEN("DISABLED"), scs);
break;
default:
@@ -5095,7 +5099,7 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
sch_table->field[ISE_ORIGINATOR]->store(et.originator, TRUE);
/* on_completion */
- if (et.on_completion == Event_timed::ON_COMPLETION_DROP)
+ if (et.on_completion == Event_parse_data::ON_COMPLETION_DROP)
sch_table->field[ISE_ON_COMPLETION]->
store(STRING_WITH_LEN("NOT PRESERVE"), scs);
else
@@ -5145,7 +5149,7 @@ copy_event_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table)
DBUG_RETURN(0);
}
-
+#endif
int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond)
{
@@ -6541,8 +6545,10 @@ ST_SCHEMA_TABLE schema_tables[]=
fill_schema_column_privileges, 0, 0, -1, -1, 0, 0},
{"ENGINES", engines_fields_info, create_schema_table,
fill_schema_engines, make_old_format, 0, -1, -1, 0, 0},
+#ifdef HAVE_EVENT_SCHEDULER
{"EVENTS", events_fields_info, create_schema_table,
Events::fill_schema_events, make_old_format, 0, -1, -1, 0, 0},
+#endif
{"FILES", files_fields_info, create_schema_table,
fill_schema_files, 0, 0, -1, -1, 0, 0},
{"GLOBAL_STATUS", variables_fields_info, create_schema_table,
diff --git a/sql/sql_test.cc b/sql/sql_test.cc
index 1a522b852e9..01363714484 100644
--- a/sql/sql_test.cc
+++ b/sql/sql_test.cc
@@ -27,7 +27,9 @@
#include <sys/malloc.h>
#endif
+#ifdef HAVE_EVENT_SCHEDULER
#include "events.h"
+#endif
static const char *lock_descriptions[] =
{
@@ -539,6 +541,8 @@ Estimated memory (with thread stack): %ld\n",
(long) (thread_count * my_thread_stack_size + info.hblkhd + info.arena));
#endif
+#ifdef HAVE_EVENT_SCHEDULER
Events::dump_internal_status();
+#endif
puts("");
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index 0e5240fea10..47ee742ffb5 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -42,7 +42,7 @@
#include "sp_pcontext.h"
#include "sp_rcontext.h"
#include "sp.h"
-#include "event_data_objects.h"
+#include "event_parse_data.h"
#include <myisam.h>
#include <myisammrg.h>
@@ -1783,7 +1783,6 @@ event_tail:
LEX *lex=Lex;
lex->create_info.options= $2;
-
if (!(lex->event_parse_data= Event_parse_data::new_instance(thd)))
MYSQL_YYABORT;
lex->event_parse_data->identifier= $3;
@@ -1840,17 +1839,17 @@ opt_ev_status:
/* empty */ { $$= 0; }
| ENABLE_SYM
{
- Lex->event_parse_data->status= Event_basic::ENABLED;
+ Lex->event_parse_data->status= Event_parse_data::ENABLED;
$$= 1;
}
| DISABLE_SYM ON SLAVE
{
- Lex->event_parse_data->status= Event_basic::SLAVESIDE_DISABLED;
+ Lex->event_parse_data->status= Event_parse_data::SLAVESIDE_DISABLED;
$$= 1;
}
| DISABLE_SYM
{
- Lex->event_parse_data->status= Event_basic::DISABLED;
+ Lex->event_parse_data->status= Event_parse_data::DISABLED;
$$= 1;
}
;
@@ -1883,13 +1882,13 @@ ev_on_completion:
ON COMPLETION_SYM PRESERVE_SYM
{
Lex->event_parse_data->on_completion=
- Event_basic::ON_COMPLETION_PRESERVE;
+ Event_parse_data::ON_COMPLETION_PRESERVE;
$$= 1;
}
| ON COMPLETION_SYM NOT_SYM PRESERVE_SYM
{
Lex->event_parse_data->on_completion=
- Event_basic::ON_COMPLETION_DROP;
+ Event_parse_data::ON_COMPLETION_DROP;
$$= 1;
}
;