summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xBUILD/SETUP.sh2
-rw-r--r--include/my_sys.h1
-rw-r--r--libmysqld/Makefile.am4
-rw-r--r--mysys/array.c25
-rw-r--r--sql/Makefile.am4
-rw-r--r--sql/lex.h8
-rw-r--r--sql/mysqld.cc12
-rw-r--r--sql/set_var.cc4
-rw-r--r--sql/share/errmsg.txt16
-rw-r--r--sql/sp.cc88
-rw-r--r--sql/sp.h12
-rw-r--r--sql/sql_acl.cc4
-rw-r--r--sql/sql_acl.h3
-rw-r--r--sql/sql_lex.cc4
-rw-r--r--sql/sql_lex.h7
-rw-r--r--sql/sql_parse.cc128
-rw-r--r--sql/sql_show.cc5
-rw-r--r--sql/sql_yacc.yy401
-rw-r--r--sql/table.cc3
-rw-r--r--sql/tztime.cc12
-rw-r--r--sql/tztime.h1
21 files changed, 676 insertions, 68 deletions
diff --git a/BUILD/SETUP.sh b/BUILD/SETUP.sh
index eece41d72e6..7881459d086 100755
--- a/BUILD/SETUP.sh
+++ b/BUILD/SETUP.sh
@@ -79,7 +79,7 @@ fast_cflags="-O3 -fno-omit-frame-pointer"
reckless_cflags="-O3 -fomit-frame-pointer "
debug_cflags="-DUNIV_MUST_NOT_INLINE -DEXTRA_DEBUG -DFORCE_INIT_OF_VARS -DSAFEMALLOC -DPEDANTIC_SAFEMALLOC -DSAFE_MUTEX"
-debug_extra_cflags="-O1 -Wuninitialized"
+debug_extra_cflags="-O0"
base_cxxflags="-felide-constructors -fno-exceptions -fno-rtti"
amd64_cxxflags="" # If dropping '--with-big-tables', add here "-DBIG_TABLES"
diff --git a/include/my_sys.h b/include/my_sys.h
index 44fe383bf4f..a814b7f66f6 100644
--- a/include/my_sys.h
+++ b/include/my_sys.h
@@ -751,6 +751,7 @@ extern void get_dynamic(DYNAMIC_ARRAY *array,gptr element,uint array_index);
extern void delete_dynamic(DYNAMIC_ARRAY *array);
extern void delete_dynamic_element(DYNAMIC_ARRAY *array, uint array_index);
extern void freeze_size(DYNAMIC_ARRAY *array);
+extern int get_index_dynamic(DYNAMIC_ARRAY *array, gptr element);
#define dynamic_array_ptr(array,array_index) ((array)->buffer+(array_index)*(array)->size_of_element)
#define dynamic_element(array,array_index,type) ((type)((array)->buffer) +(array_index))
#define push_dynamic(A,B) insert_dynamic(A,B)
diff --git a/libmysqld/Makefile.am b/libmysqld/Makefile.am
index da0418eaf9c..4eae790c9db 100644
--- a/libmysqld/Makefile.am
+++ b/libmysqld/Makefile.am
@@ -62,8 +62,8 @@ sqlsources = derror.cc field.cc field_conv.cc strfunc.cc filesort.cc \
unireg.cc uniques.cc stacktrace.c sql_union.cc hash_filo.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 \
- rpl_filter.cc sql_partition.cc handlerton.cc sql_plugin.cc
+ parse_file.cc sql_view.cc sql_trigger.cc my_decimal.cc event.cc \
+ rpl_filter.cc sql_partition.cc handlerton.cc sql_plugin.cc
libmysqld_int_a_SOURCES= $(libmysqld_sources) $(libmysqlsources) $(sqlsources)
EXTRA_libmysqld_a_SOURCES = ha_innodb.cc ha_berkeley.cc ha_archive.cc \
diff --git a/mysys/array.c b/mysys/array.c
index 6d00585f24d..a50d8b78178 100644
--- a/mysys/array.c
+++ b/mysys/array.c
@@ -278,3 +278,28 @@ void freeze_size(DYNAMIC_ARRAY *array)
array->max_element=elements;
}
}
+
+
+/*
+ Get the index of a dynamic element
+
+ SYNOPSIS
+ get_index_dynamic()
+ array Array
+ element Whose element index
+
+*/
+
+int get_index_dynamic(DYNAMIC_ARRAY *array, gptr element)
+{
+ uint ret;
+ if (array->buffer > element)
+ return -1;
+
+ ret= (element - array->buffer) / array->size_of_element;
+ if (ret > array->elements)
+ return -1;
+
+ return ret;
+
+}
diff --git a/sql/Makefile.am b/sql/Makefile.am
index 78d5e262fde..0182e58ba6c 100644
--- a/sql/Makefile.am
+++ b/sql/Makefile.am
@@ -61,7 +61,7 @@ noinst_HEADERS = item.h item_func.h item_sum.h item_cmpfunc.h \
tztime.h my_decimal.h\
sp_head.h sp_pcontext.h sp_rcontext.h sp.h sp_cache.h \
parse_file.h sql_view.h sql_trigger.h \
- sql_array.h sql_cursor.h \
+ sql_array.h sql_cursor.h event.h \
sql_plugin.h authors.h
mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
item.cc item_sum.cc item_buff.cc item_func.cc \
@@ -94,7 +94,7 @@ mysqld_SOURCES = sql_lex.cc sql_handler.cc sql_partition.cc \
gstream.cc spatial.cc sql_help.cc sql_cursor.cc \
tztime.cc my_time.c my_decimal.cc\
sp_head.cc sp_pcontext.cc sp_rcontext.cc sp.cc \
- sp_cache.cc parse_file.cc sql_trigger.cc \
+ sp_cache.cc parse_file.cc sql_trigger.cc event.cc \
sql_plugin.cc\
handlerton.cc
EXTRA_mysqld_SOURCES = ha_innodb.cc ha_berkeley.cc ha_archive.cc \
diff --git a/sql/lex.h b/sql/lex.h
index e3cbebf4629..41cbae0adea 100644
--- a/sql/lex.h
+++ b/sql/lex.h
@@ -74,6 +74,7 @@ static SYMBOL symbols[] = {
{ "ASC", SYM(ASC)},
{ "ASCII", SYM(ASCII_SYM)},
{ "ASENSITIVE", SYM(ASENSITIVE_SYM)},
+ { "AT", SYM(AT_SYM)},
{ "AUTHORS", SYM(AUTHORS_SYM)},
{ "AUTO_INCREMENT", SYM(AUTO_INC)},
{ "AVG", SYM(AVG_SYM)},
@@ -121,6 +122,7 @@ static SYMBOL symbols[] = {
{ "COMMIT", SYM(COMMIT_SYM)},
{ "COMMITTED", SYM(COMMITTED_SYM)},
{ "COMPACT", SYM(COMPACT_SYM)},
+ { "COMPLETION", SYM(COMPLETION_SYM)},
{ "COMPRESSED", SYM(COMPRESSED_SYM)},
{ "CONCURRENT", SYM(CONCURRENT)},
{ "CONDITION", SYM(CONDITION_SYM)},
@@ -180,13 +182,16 @@ static SYMBOL symbols[] = {
{ "ENABLE", SYM(ENABLE_SYM)},
{ "ENCLOSED", SYM(ENCLOSED)},
{ "END", SYM(END)},
+ { "ENDS", SYM(ENDS_SYM)},
{ "ENGINE", SYM(ENGINE_SYM)},
{ "ENGINES", SYM(ENGINES_SYM)},
{ "ENUM", SYM(ENUM)},
{ "ERRORS", SYM(ERRORS)},
{ "ESCAPE", SYM(ESCAPE_SYM)},
{ "ESCAPED", SYM(ESCAPED)},
+ { "EVENT", SYM(EVENT_SYM)},
{ "EVENTS", SYM(EVENTS_SYM)},
+ { "EVERY", SYM(EVERY_SYM)},
{ "EXECUTE", SYM(EXECUTE_SYM)},
{ "EXISTS", SYM(EXISTS)},
{ "EXIT", SYM(EXIT_SYM)},
@@ -384,6 +389,7 @@ static SYMBOL symbols[] = {
{ "POLYGON", SYM(POLYGON)},
{ "PRECISION", SYM(PRECISION)},
{ "PREPARE", SYM(PREPARE_SYM)},
+ { "PRESERVE", SYM(PRESERVE_SYM)},
{ "PREV", SYM(PREV_SYM)},
{ "PRIMARY", SYM(PRIMARY_SYM)},
{ "PRIVILEGES", SYM(PRIVILEGES)},
@@ -436,6 +442,7 @@ static SYMBOL symbols[] = {
{ "ROW_FORMAT", SYM(ROW_FORMAT_SYM)},
{ "RTREE", SYM(RTREE_SYM)},
{ "SAVEPOINT", SYM(SAVEPOINT_SYM)},
+ { "SCHEDULE", SYM(SCHEDULE_SYM)},
{ "SCHEMA", SYM(DATABASE)},
{ "SCHEMAS", SYM(DATABASES)},
{ "SECOND", SYM(SECOND_SYM)},
@@ -484,6 +491,7 @@ static SYMBOL symbols[] = {
{ "SSL", SYM(SSL_SYM)},
{ "START", SYM(START_SYM)},
{ "STARTING", SYM(STARTING)},
+ { "STARTS", SYM(STARTS_SYM)},
{ "STATUS", SYM(STATUS_SYM)},
{ "STOP", SYM(STOP_SYM)},
{ "STORAGE", SYM(STORAGE_SYM)},
diff --git a/sql/mysqld.cc b/sql/mysqld.cc
index 68485600e9e..65ef17b7066 100644
--- a/sql/mysqld.cc
+++ b/sql/mysqld.cc
@@ -24,6 +24,7 @@
#include "stacktrace.h"
#include "mysqld_suffix.h"
#include "mysys_err.h"
+#include "event.h"
#include "ha_myisam.h"
@@ -3502,6 +3503,8 @@ we force server id to 2, but this MySQL server will not act as a slave.");
}
}
+ init_events();
+
create_shutdown_thread();
create_maintenance_thread();
@@ -4526,7 +4529,7 @@ enum options_mysqld
OPT_MAX_BINLOG_DUMP_EVENTS, OPT_SPORADIC_BINLOG_DUMP_FAIL,
OPT_SAFE_USER_CREATE, OPT_SQL_MODE,
OPT_HAVE_NAMED_PIPE,
- OPT_DO_PSTACK, OPT_REPORT_HOST,
+ OPT_DO_PSTACK, OPT_EVENT_EXECUTOR, OPT_REPORT_HOST,
OPT_REPORT_USER, OPT_REPORT_PASSWORD, OPT_REPORT_PORT,
OPT_SHOW_SLAVE_AUTH_INFO,
OPT_SLAVE_LOAD_TMPDIR, OPT_NO_MIX_TYPE,
@@ -4804,6 +4807,9 @@ Disable with --skip-bdb (will save memory).",
(gptr*) &global_system_variables.engine_condition_pushdown,
(gptr*) &global_system_variables.engine_condition_pushdown,
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
+ {"event-executor", OPT_EVENT_EXECUTOR, "Print a symbolic stack trace on failure.",
+ (gptr*) &opt_event_executor, (gptr*) &opt_event_executor, 0, GET_BOOL, NO_ARG,
+ 1/*default*/, 0/*min-value*/, 1/*max-value*/, 0, 0, 0},
{"exit-info", 'T', "Used for debugging; Use at your own risk!", 0, 0, 0,
GET_LONG, OPT_ARG, 0, 0, 0, 0, 0, 0},
{"external-locking", OPT_USE_LOCKING, "Use system (external) locking. With this option enabled you can run myisamchk to test (not repair) tables while the MySQL server is running.",
@@ -6028,6 +6034,7 @@ struct show_var_st status_vars[]= {
{"Bytes_sent", (char*) offsetof(STATUS_VAR, bytes_sent), SHOW_LONG_STATUS},
{"Com_admin_commands", (char*) offsetof(STATUS_VAR, com_other), SHOW_LONG_STATUS},
{"Com_alter_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ALTER_DB]), SHOW_LONG_STATUS},
+ {"Com_alter_event", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ALTER_EVENT]), SHOW_LONG_STATUS},
{"Com_alter_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ALTER_TABLE]), SHOW_LONG_STATUS},
{"Com_analyze", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_ANALYZE]), SHOW_LONG_STATUS},
{"Com_backup_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_BACKUP_TABLE]), SHOW_LONG_STATUS},
@@ -6038,6 +6045,7 @@ struct show_var_st status_vars[]= {
{"Com_checksum", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CHECKSUM]), SHOW_LONG_STATUS},
{"Com_commit", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_COMMIT]), SHOW_LONG_STATUS},
{"Com_create_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CREATE_DB]), SHOW_LONG_STATUS},
+ {"Com_create_event", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CREATE_EVENT]), SHOW_LONG_STATUS},
{"Com_create_function", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CREATE_FUNCTION]), SHOW_LONG_STATUS},
{"Com_create_index", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CREATE_INDEX]), SHOW_LONG_STATUS},
{"Com_create_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_CREATE_TABLE]), SHOW_LONG_STATUS},
@@ -6046,6 +6054,7 @@ struct show_var_st status_vars[]= {
{"Com_delete_multi", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DELETE_MULTI]), SHOW_LONG_STATUS},
{"Com_do", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DO]), SHOW_LONG_STATUS},
{"Com_drop_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_DB]), SHOW_LONG_STATUS},
+ {"Com_drop_event", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_EVENT]), SHOW_LONG_STATUS},
{"Com_drop_function", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_FUNCTION]), SHOW_LONG_STATUS},
{"Com_drop_index", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_INDEX]), SHOW_LONG_STATUS},
{"Com_drop_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_DROP_TABLE]), SHOW_LONG_STATUS},
@@ -6087,6 +6096,7 @@ struct show_var_st status_vars[]= {
{"Com_show_collations", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_COLLATIONS]), SHOW_LONG_STATUS},
{"Com_show_column_types", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_COLUMN_TYPES]), SHOW_LONG_STATUS},
{"Com_show_create_db", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CREATE_DB]), SHOW_LONG_STATUS},
+ {"Com_show_create_event", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CREATE_EVENT]), SHOW_LONG_STATUS},
{"Com_show_create_table", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_CREATE]), SHOW_LONG_STATUS},
{"Com_show_databases", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_DATABASES]), SHOW_LONG_STATUS},
{"Com_show_engine_logs", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_ENGINE_LOGS]), SHOW_LONG_STATUS},
diff --git a/sql/set_var.cc b/sql/set_var.cc
index b505f8cdc2a..b74914e72a6 100644
--- a/sql/set_var.cc
+++ b/sql/set_var.cc
@@ -102,6 +102,7 @@ extern ulong ndb_cache_check_time;
+extern my_bool event_executor_running_global_var;
static HASH system_variable_hash;
const char *bool_type_names[]= { "OFF", "ON", NullS };
@@ -206,6 +207,8 @@ sys_var_long_ptr sys_delayed_insert_timeout("delayed_insert_timeout",
&delayed_insert_timeout);
sys_var_long_ptr sys_delayed_queue_size("delayed_queue_size",
&delayed_queue_size);
+sys_var_bool_ptr sys_event_executor("event_executor",
+ &event_executor_running_global_var);
sys_var_long_ptr sys_expire_logs_days("expire_logs_days",
&expire_logs_days);
sys_var_bool_ptr sys_flush("flush", &myisam_flush);
@@ -664,6 +667,7 @@ struct show_var_st init_vars[]= {
{sys_div_precincrement.name,(char*) &sys_div_precincrement,SHOW_SYS},
{sys_engine_condition_pushdown.name,
(char*) &sys_engine_condition_pushdown, SHOW_SYS},
+ {sys_event_executor.name, (char*) &sys_event_executor, SHOW_SYS},
{sys_expire_logs_days.name, (char*) &sys_expire_logs_days, SHOW_SYS},
{sys_flush.name, (char*) &sys_flush, SHOW_SYS},
{sys_flush_time.name, (char*) &sys_flush_time, SHOW_SYS},
diff --git a/sql/share/errmsg.txt b/sql/share/errmsg.txt
index f556ad9db65..dfe1f2d71ad 100644
--- a/sql/share/errmsg.txt
+++ b/sql/share/errmsg.txt
@@ -5721,3 +5721,19 @@ ER_DROP_PARTITION_WHEN_FK_DEFINED
swe "Kan inte ta bort en partition när en främmande nyckel är definierad på tabellen"
ER_PLUGIN_IS_NOT_LOADED
eng "Plugin '%-.64s' is not loaded"
+ER_EVENT_ALREADY_EXISTS
+ eng "Event %s already exists"
+ER_EVENT_STORE_FAILED
+ eng "Failed to create event %s"
+ER_EVENT_DOES_NOT_EXIST
+ eng "Event %s does not exist"
+ER_EVENT_CANT_ALTER
+ eng "Failed to alter event %s"
+ER_EVENT_DROP_FAILED
+ eng "Failed to DROP %s %s"
+ER_EVENT_INTERVAL_NOT_POSITIVE
+ eng "INTERVAL must be positive"
+ER_EVENT_ENDS_BEFORE_STARTS
+ eng "ENDS must be after STARTS"
+ER_EVENT_EXEC_TIME_IN_THE_PAST
+ eng "Activation (AT) time is in the past"
diff --git a/sql/sp.cc b/sql/sp.cc
index e9deb9b73c4..cda6454b891 100644
--- a/sql/sp.cc
+++ b/sql/sp.cc
@@ -20,6 +20,9 @@
#include "sp_cache.h"
#include "sql_trigger.h"
+#define SP_OPEN_TABLE_FOR_UPDATE() \
+ open_proc_type_table_for_update(thd, "proc", &mysql_proc_table_exists)
+
static bool
create_string(THD *thd, String *buf,
int sp_type,
@@ -68,7 +71,7 @@ bool mysql_proc_table_exists= 1;
/*
- Close mysql.proc, opened with open_proc_table_for_read().
+ Close mysql.proc, opened with open_proc_type_table_for_read().
SYNOPSIS
close_proc_table()
@@ -86,14 +89,16 @@ void close_proc_table(THD *thd, Open_tables_state *backup)
/*
- Open the mysql.proc table for read.
+ Open table which has key structure like of mysql.proc for read.
SYNOPSIS
- open_proc_table_for_read()
- thd Thread context
- backup Pointer to Open_tables_state instance where information about
- currently open tables will be saved, and from which will be
- restored when we will end work with mysql.proc.
+ open_proc_type_table_for_read()
+ thd Thread context
+ backup Pointer to Open_tables_state instance where information about
+ currently open tables will be saved, and from which will be
+ restored when we will end work with mysql.proc.
+ tname Table name having primary key structure like mysql.proc
+ table_exists Ptr to boolean to set whether the system table exists or not
NOTES
Thanks to restrictions which we put on opening and locking of
@@ -104,10 +109,11 @@ void close_proc_table(THD *thd, Open_tables_state *backup)
RETURN
0 Error
- # Pointer to TABLE object of mysql.proc
+ # Pointer to TABLE object of tname
*/
-TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
+TABLE *open_proc_type_table_for_read(THD *thd, Open_tables_state *backup,
+ const char *tname, bool *table_exists)
{
TABLE_LIST tables;
TABLE *table;
@@ -115,22 +121,22 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
DBUG_ENTER("open_proc_table");
/*
- Speed up things if mysql.proc doesn't exists. mysql_proc_table_exists
+ Speed up things if the table doesn't exists. *table_exists
is set when we create or read stored procedure or on flush privileges.
*/
- if (!mysql_proc_table_exists)
+ if (!*table_exists)
DBUG_RETURN(0);
thd->reset_n_backup_open_tables_state(backup);
bzero((char*) &tables, sizeof(tables));
tables.db= (char*) "mysql";
- tables.table_name= tables.alias= (char*)"proc";
+ tables.table_name= tables.alias= (char*) tname;
if (!(table= open_table(thd, &tables, thd->mem_root, &not_used,
MYSQL_LOCK_IGNORE_FLUSH)))
{
thd->restore_backup_open_tables_state(backup);
- mysql_proc_table_exists= 0;
+ *table_exists= 0;
DBUG_RETURN(0);
}
@@ -152,11 +158,13 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
/*
- Open the mysql.proc table for update.
+ Open table with primary key struct like mysql.proc for update.
SYNOPSIS
- open_proc_table_for_update()
- thd Thread context
+ open_proc_type_table_for_update()
+ thd Thread context
+ tname Table name with primary key structure like mysql.proc
+ table_exists Ptr to boolean to set whether the system table exists or not
NOTES
Table opened with this call should closed using close_thread_tables().
@@ -166,7 +174,8 @@ TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup)
# Pointer to TABLE object of mysql.proc
*/
-static TABLE *open_proc_table_for_update(THD *thd)
+TABLE *open_proc_type_table_for_update(THD *thd, const char *tname,
+ bool *table_exists)
{
TABLE_LIST tables;
TABLE *table;
@@ -174,7 +183,7 @@ static TABLE *open_proc_table_for_update(THD *thd)
bzero((char*) &tables, sizeof(tables));
tables.db= (char*) "mysql";
- tables.table_name= tables.alias= (char*)"proc";
+ tables.table_name= tables.alias= (char*) tname;
tables.lock_type= TL_WRITE;
table= open_ltable(thd, &tables, TL_WRITE);
@@ -186,7 +195,7 @@ static TABLE *open_proc_table_for_update(THD *thd)
transient.
*/
if (!(thd->locked_tables || thd->prelocked_mode) || table)
- mysql_proc_table_exists= test(table);
+ *table_exists= test(table);
DBUG_RETURN(table);
}
@@ -196,10 +205,11 @@ static TABLE *open_proc_table_for_update(THD *thd)
Find row in open mysql.proc table representing stored routine.
SYNOPSIS
- db_find_routine_aux()
+ sp_db_find_routine_aux()
thd Thread context
type Type of routine to find (function or procedure)
- name Name of routine
+ dbname Name of routine's database
+ rname Name of the routine inside the db
table TABLE object for open mysql.proc table.
RETURN VALUE
@@ -207,13 +217,14 @@ static TABLE *open_proc_table_for_update(THD *thd)
SP_KEY_NOT_FOUND- No routine with given name
*/
-static int
-db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table)
+int
+sp_db_find_routine_aux(THD *thd, int type, const LEX_STRING dbname,
+ const LEX_STRING rname, TABLE *table)
{
byte key[MAX_KEY_LENGTH]; // db, name, optional key length type
- DBUG_ENTER("db_find_routine_aux");
+ DBUG_ENTER("sp_db_find_routine_aux");
DBUG_PRINT("enter", ("type: %d name: %.*s",
- type, name->m_name.length, name->m_name.str));
+ type, rname.length, rname.str));
/*
Create key to find row. We have to use field->store() to be able to
@@ -222,11 +233,10 @@ db_find_routine_aux(THD *thd, int type, sp_name *name, TABLE *table)
'db', 'name' and 'type' and the first key is the primary key over the
same fields.
*/
- if (name->m_name.length > table->field[1]->field_length)
+ if (rname.length > table->field[1]->field_length)
DBUG_RETURN(SP_KEY_NOT_FOUND);
- table->field[0]->store(name->m_db.str, name->m_db.length, &my_charset_bin);
- table->field[1]->store(name->m_name.str, name->m_name.length,
- &my_charset_bin);
+ table->field[0]->store(dbname.str, dbname.length, &my_charset_bin);
+ table->field[1]->store(rname.str, rname.length, &my_charset_bin);
table->field[2]->store((longlong) type, TRUE);
key_copy(key, table->record[0], table->key_info,
table->key_info->key_length);
@@ -283,10 +293,12 @@ db_find_routine(THD *thd, int type, sp_name *name, sp_head **sphp)
type, name->m_name.length, name->m_name.str));
*sphp= 0; // In case of errors
- if (!(table= open_proc_table_for_read(thd, &open_tables_state_backup)))
+ if (!(table= open_proc_type_table_for_read(thd,&open_tables_state_backup,
+ "proc", &mysql_proc_table_exists)))
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
- if ((ret= db_find_routine_aux(thd, type, name, table)) != SP_OK)
+ if ((ret= sp_db_find_routine_aux(thd, type, name->m_db, name->m_name,
+ table)) != SP_OK)
goto done;
if (table->s->fields != MYSQL_PROC_FIELD_COUNT)
@@ -493,7 +505,7 @@ db_create_routine(THD *thd, int type, sp_head *sp)
goto done;
}
- if (!(table= open_proc_table_for_update(thd)))
+ if (!(table= SP_OPEN_TABLE_FOR_UPDATE()))
ret= SP_OPEN_TABLE_FAILED;
else
{
@@ -614,9 +626,10 @@ db_drop_routine(THD *thd, int type, sp_name *name)
DBUG_PRINT("enter", ("type: %d name: %.*s",
type, name->m_name.length, name->m_name.str));
- if (!(table= open_proc_table_for_update(thd)))
+ if (!(table= SP_OPEN_TABLE_FOR_UPDATE()))
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
- if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK)
+ if ((ret= sp_db_find_routine_aux(thd, type, name->m_db, name->m_name,
+ table)) == SP_OK)
{
if (table->file->delete_row(table->record[0]))
ret= SP_DELETE_ROW_FAILED;
@@ -636,9 +649,10 @@ db_update_routine(THD *thd, int type, sp_name *name, st_sp_chistics *chistics)
DBUG_PRINT("enter", ("type: %d name: %.*s",
type, name->m_name.length, name->m_name.str));
- if (!(table= open_proc_table_for_update(thd)))
+ if (!(table= SP_OPEN_TABLE_FOR_UPDATE()))
DBUG_RETURN(SP_OPEN_TABLE_FAILED);
- if ((ret= db_find_routine_aux(thd, type, name, table)) == SP_OK)
+ if ((ret= sp_db_find_routine_aux(thd, type, name->m_db, name->m_name,
+ table)) == SP_OK)
{
store_record(table,record[1]);
table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET;
@@ -860,7 +874,7 @@ sp_drop_db_routines(THD *thd, char *db)
keylen= sizeof(key);
ret= SP_OPEN_TABLE_FAILED;
- if (!(table= open_proc_table_for_update(thd)))
+ if (!(table= SP_OPEN_TABLE_FOR_UPDATE()))
goto err;
ret= SP_OK;
diff --git a/sql/sp.h b/sql/sp.h
index 7f314b8903e..157d7dbbea9 100644
--- a/sql/sp.h
+++ b/sql/sp.h
@@ -31,6 +31,8 @@
#define SP_BAD_IDENTIFIER -9
#define SP_BODY_TOO_LONG -10
+extern bool mysql_proc_table_exists;
+
/* Drop all routines in database 'db' */
int
sp_drop_db_routines(THD *thd, char *db);
@@ -97,9 +99,17 @@ extern "C" byte* sp_sroutine_key(const byte *ptr, uint *plen, my_bool first);
Routines which allow open/lock and close mysql.proc table even when
we already have some tables open and locked.
*/
-TABLE *open_proc_table_for_read(THD *thd, Open_tables_state *backup);
+TABLE *open_proc_type_table_for_read(THD *thd, Open_tables_state *backup,
+ const char *tname, bool *table_exists);
+TABLE *open_proc_type_table_for_update(THD *thd, const char *tname,
+ bool *table_exists);
+
void close_proc_table(THD *thd, Open_tables_state *backup);
+int
+sp_db_find_routine_aux(THD *thd, int type, const LEX_STRING dbname,
+ const LEX_STRING rname, TABLE *table);
+
//
// Utilities...
//
diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc
index 59f1e91e2e5..427193cb4a8 100644
--- a/sql/sql_acl.cc
+++ b/sql/sql_acl.cc
@@ -3971,13 +3971,13 @@ static const char *command_array[]=
"ALTER", "SHOW DATABASES", "SUPER", "CREATE TEMPORARY TABLES",
"LOCK TABLES", "EXECUTE", "REPLICATION SLAVE", "REPLICATION CLIENT",
"CREATE VIEW", "SHOW VIEW", "CREATE ROUTINE", "ALTER ROUTINE",
- "CREATE USER"
+ "CREATE USER", "EVENT"
};
static uint command_lengths[]=
{
6, 6, 6, 6, 6, 4, 6, 8, 7, 4, 5, 10, 5, 5, 14, 5, 23, 11, 7, 17, 18, 11, 9,
- 14, 13, 11
+ 14, 13, 11, 5
};
diff --git a/sql/sql_acl.h b/sql/sql_acl.h
index 0a9c6ba785f..c1e0e94dd06 100644
--- a/sql/sql_acl.h
+++ b/sql/sql_acl.h
@@ -42,6 +42,7 @@
#define CREATE_PROC_ACL (1L << 23)
#define ALTER_PROC_ACL (1L << 24)
#define CREATE_USER_ACL (1L << 25)
+#define EVENT_ACL (1L << 26)
/*
don't forget to update
1. static struct show_privileges_st sys_privileges[]
@@ -78,7 +79,7 @@
REFERENCES_ACL | INDEX_ACL | ALTER_ACL | SHOW_DB_ACL | SUPER_ACL | \
CREATE_TMP_ACL | LOCK_TABLES_ACL | REPL_SLAVE_ACL | REPL_CLIENT_ACL | \
EXECUTE_ACL | CREATE_VIEW_ACL | SHOW_VIEW_ACL | CREATE_PROC_ACL | \
- ALTER_PROC_ACL | CREATE_USER_ACL)
+ ALTER_PROC_ACL | CREATE_USER_ACL | EVENT_ACL)
#define DEFAULT_CREATE_PROC_ACLS \
(ALTER_PROC_ACL | EXECUTE_ACL)
diff --git a/sql/sql_lex.cc b/sql/sql_lex.cc
index 4d32e26f1b7..f2f065510da 100644
--- a/sql/sql_lex.cc
+++ b/sql/sql_lex.cc
@@ -177,7 +177,9 @@ void lex_start(THD *thd, const uchar *buf, uint length)
lex->spcont= NULL;
lex->proc_list.first= 0;
lex->query_tables_own_last= 0;
- lex->escape_used= FALSE;
+ lex->escape_used= lex->et_compile_phase= FALSE;
+
+ lex->et= NULL;
if (lex->sroutines.records)
my_hash_reset(&lex->sroutines);
diff --git a/sql/sql_lex.h b/sql/sql_lex.h
index d7ad28a95f5..fdcd785f920 100644
--- a/sql/sql_lex.h
+++ b/sql/sql_lex.h
@@ -26,6 +26,7 @@ class sp_name;
class sp_instr;
class sp_pcontext;
class partition_info;
+class event_timed;
/*
The following hack is needed because mysql_yacc.cc does not define
@@ -94,6 +95,8 @@ enum enum_sql_command {
SQLCOM_SHOW_PROC_CODE, SQLCOM_SHOW_FUNC_CODE,
SQLCOM_INSTALL_PLUGIN, SQLCOM_UNINSTALL_PLUGIN,
SQLCOM_SHOW_AUTHORS,
+ SQLCOM_CREATE_EVENT, SQLCOM_ALTER_EVENT, SQLCOM_DROP_EVENT,
+ SQLCOM_SHOW_CREATE_EVENT,
/* This should be the last !!! */
SQLCOM_END
@@ -890,6 +893,10 @@ typedef struct st_lex
uint sroutines_list_own_elements;
st_sp_chistics sp_chistics;
+
+ event_timed *et;
+ bool et_compile_phase;
+
bool only_view; /* used for SHOW CREATE TABLE/VIEW */
/*
field_list was created for view and should be removed before PS/SP
diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc
index 57d7059dd8f..d316906f1f6 100644
--- a/sql/sql_parse.cc
+++ b/sql/sql_parse.cc
@@ -25,6 +25,7 @@
#include "sp_head.h"
#include "sp.h"
#include "sp_cache.h"
+#include "event.h"
#ifdef HAVE_OPENSSL
/*
@@ -642,6 +643,9 @@ void init_update_queries(void)
uc_update_queries[SQLCOM_DROP_INDEX]=1;
uc_update_queries[SQLCOM_CREATE_VIEW]=1;
uc_update_queries[SQLCOM_DROP_VIEW]=1;
+ uc_update_queries[SQLCOM_CREATE_EVENT]=1;
+ uc_update_queries[SQLCOM_ALTER_EVENT]=1;
+ uc_update_queries[SQLCOM_DROP_EVENT]=1;
}
bool is_update_query(enum enum_sql_command command)
@@ -3669,6 +3673,130 @@ end_with_restore_list:
res=mysqld_show_create_db(thd,lex->name,&lex->create_info);
break;
}
+ case SQLCOM_CREATE_EVENT:
+ {
+ if (check_global_access(thd, EVENT_ACL))
+ break;
+
+ DBUG_ASSERT(lex->et);
+ if (! lex->et->m_db.str)
+ {
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+ delete lex->et;
+ lex->et= 0;
+ goto error;
+ }
+
+ int result;
+ uint create_options= lex->create_info.options;
+ res= (result= evex_create_event(thd, lex->et, create_options));
+ switch (result) {
+ case EVEX_OK:
+ send_ok(thd, 1);
+ break;
+ case EVEX_WRITE_ROW_FAILED:
+ my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), lex->et->m_name.str);
+ break;
+ case EVEX_NO_DB_ERROR:
+ my_error(ER_BAD_DB_ERROR, MYF(0), lex->et->m_db.str);
+ break;
+ default:
+ //includes EVEX_PARSE_ERROR
+ my_error(ER_EVENT_STORE_FAILED, MYF(0), lex->et->m_name.str);
+ break;
+ }
+ /* lex->unit.cleanup() is called outside, no need to call it here */
+ delete lex->et;
+ lex->et= 0;
+
+ delete lex->sphead;
+ lex->sphead= 0;
+
+ break;
+ }
+ case SQLCOM_ALTER_EVENT:
+ {
+ if (check_global_access(thd, EVENT_ACL))
+ break;
+
+ DBUG_ASSERT(lex->et);
+ if (! lex->et->m_db.str)
+ {
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+ delete lex->et;
+ lex->et= 0;
+ goto error;
+ }
+
+ int result;
+ res= (result= evex_update_event(thd, lex->spname, lex->et));
+ switch (result) {
+ case EVEX_OK:
+ send_ok(thd, 1);
+ break;
+ case EVEX_KEY_NOT_FOUND:
+ my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), lex->et->m_qname.str);
+ break;
+ default:
+ my_error(ER_EVENT_CANT_ALTER, MYF(0), lex->et->m_qname.str);
+ break;
+ }
+ delete lex->et;
+ lex->et= 0;
+
+ if (lex->sphead)
+ {
+ delete lex->sphead;
+ lex->sphead= 0;
+ }
+
+ break;
+ }
+ case SQLCOM_DROP_EVENT:
+ {
+ if (check_global_access(thd, EVENT_ACL))
+ break;
+
+ DBUG_ASSERT(lex->et);
+ if (! lex->et->m_db.str)
+ {
+ my_message(ER_NO_DB_ERROR, ER(ER_NO_DB_ERROR), MYF(0));
+ delete lex->et;
+ lex->et= 0;
+ goto error;
+ }
+
+ int result;
+ res= (result= evex_drop_event(thd, lex->et, lex->drop_if_exists));
+ switch (result) {
+ case EVEX_OK:
+ send_ok(thd, 1);
+ break;
+ case EVEX_KEY_NOT_FOUND:
+ my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), lex->et->m_qname.str);
+ break;
+ default:
+ my_error(ER_EVENT_DROP_FAILED, MYF(0), lex->et->m_qname.str);
+ break;
+ }
+ delete lex->et;
+ lex->et= 0;
+
+ break;
+ }
+ case SQLCOM_SHOW_CREATE_EVENT:
+ {
+ if (check_global_access(thd, EVENT_ACL))
+ break;
+
+ if (lex->spname->m_name.length > NAME_LEN)
+ {
+ my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str);
+ goto error;
+ }
+ send_ok(thd, 1);
+ break;
+ }
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 e33fc2e1c56..447201de57c 100644
--- a/sql/sql_show.cc
+++ b/sql/sql_show.cc
@@ -147,6 +147,7 @@ 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"},
+ {"Event","Server Admin","Creation, alteration, deletion and execution of events."},
{"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"},
@@ -2930,7 +2931,9 @@ int fill_schema_proc(THD *thd, TABLE_LIST *tables, COND *cond)
proc_tables.table_name_length= 4;
proc_tables.lock_type= TL_READ;
full_access= !check_table_access(thd, SELECT_ACL, &proc_tables, 1);
- if (!(proc_table= open_proc_table_for_read(thd, &open_tables_state_backup)))
+ if (!(proc_table= open_proc_type_table_for_read(thd, &open_tables_state_backup,
+ "proc",
+ &mysql_proc_table_exists)))
{
DBUG_RETURN(1);
}
diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy
index c79ad97be4e..74ea99b7d98 100644
--- a/sql/sql_yacc.yy
+++ b/sql/sql_yacc.yy
@@ -38,6 +38,7 @@
#include "sp_pcontext.h"
#include "sp_rcontext.h"
#include "sp.h"
+#include "event.h"
#include <myisam.h>
#include <myisammrg.h>
@@ -136,6 +137,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token ASC
%token ASCII_SYM
%token ASENSITIVE_SYM
+%token AT_SYM
%token ATAN
%token AUTHORS_SYM
%token AUTO_INC
@@ -186,6 +188,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token COMMITTED_SYM
%token COMMIT_SYM
%token COMPACT_SYM
+%token COMPLETION_SYM
%token COMPRESSED_SYM
%token CONCAT
%token CONCAT_WS
@@ -254,6 +257,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token ENCODE_SYM
%token ENCRYPT
%token END
+%token ENDS_SYM
%token ENGINES_SYM
%token ENGINE_SYM
%token ENUM
@@ -262,7 +266,9 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token ERRORS
%token ESCAPED
%token ESCAPE_SYM
+%token EVENT_SYM
%token EVENTS_SYM
+%token EVERY_SYM
%token EXECUTE_SYM
%token EXISTS
%token EXIT_SYM
@@ -488,6 +494,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token POSITION_SYM
%token PRECISION
%token PREPARE_SYM
+%token PRESERVE_SYM
%token PREV_SYM
%token PRIMARY_SYM
%token PRIVILEGES
@@ -544,6 +551,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token ROW_SYM
%token RTREE_SYM
%token SAVEPOINT_SYM
+%token SCHEDULE_SYM
%token SECOND_MICROSECOND_SYM
%token SECOND_SYM
%token SECURITY_SYM
@@ -583,6 +591,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token SSL_SYM
%token STARTING
%token START_SYM
+%token STARTS_SYM
%token STATUS_SYM
%token STD_SYM
%token STDDEV_SAMP_SYM
@@ -676,6 +685,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
%token YEAR_SYM
%token ZEROFILL
+
%left JOIN_SYM INNER_SYM STRAIGHT_JOIN CROSS LEFT RIGHT
/* A dummy token to force the priority of table_ref production in a join. */
%left TABLE_REF_PRIORITY
@@ -857,6 +867,12 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
END_OF_INPUT
%type <NONE> call sp_proc_stmts sp_proc_stmts1 sp_proc_stmt
+%type <NONE> sp_proc_stmt_statement sp_proc_stmt_return
+%type <NONE> sp_proc_stmt_if sp_proc_stmt_case_simple sp_proc_stmt_case
+%type <NONE> sp_labeled_control sp_proc_stmt_unlabeled sp_proc_stmt_leave
+%type <NONE> sp_proc_stmt_iterate sp_proc_stmt_label sp_proc_stmt_goto
+%type <NONE> sp_proc_stmt_open sp_proc_stmt_fetch sp_proc_stmt_close
+
%type <num> sp_decl_idents sp_opt_inout sp_handler_type sp_hcond_list
%type <spcondtype> sp_cond sp_hcond
%type <spblock> sp_decls sp_decl
@@ -1295,7 +1311,213 @@ create:
{
Lex->sql_command = SQLCOM_CREATE_USER;
}
- ;
+ | CREATE EVENT_SYM opt_if_not_exists sp_name
+ {
+ LEX *lex=Lex;
+ event_timed *et;
+
+ if (lex->et)
+ {
+ // ToDo Andrey : Change the error message
+ my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "EVENT");
+ YYABORT;
+ }
+
+ lex->create_info.options=$3;
+
+ et= new event_timed();// implicitly calls event_timed::init()
+ lex->et = et;
+
+ if (!lex->et_compile_phase)
+ et->init_name(YYTHD, $4);
+
+ /*
+ We have to turn of CLIENT_MULTI_QUERIES while parsing a
+ stored procedure, otherwise yylex will chop it into pieces
+ at each ';'.
+ */
+ et->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
+ YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
+
+ lex->sphead= 0;
+ }
+ ON SCHEDULE_SYM ev_schedule_time
+ ev_on_completion
+ ev_status
+ ev_comment
+ DO_SYM ev_sql_stmt
+ {
+ LEX *lex=Lex;
+
+ lex->sql_command= SQLCOM_CREATE_EVENT;
+ }
+ ;
+
+ev_schedule_time: EVERY_SYM expr interval
+ {
+ LEX *lex=Lex;
+ if (!lex->et_compile_phase)
+ {
+ switch (lex->et->init_interval(YYTHD , $2, $3)) {
+ case EVEX_PARSE_ERROR:
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
+ break;
+ case EVEX_BAD_PARAMS:
+ my_error(ER_EVENT_INTERVAL_NOT_POSITIVE, MYF(0));
+ YYABORT;
+ break;
+ }
+ }
+ }
+ ev_starts
+ ev_ends
+ | AT_SYM expr
+ {
+ LEX *lex=Lex;
+ if (!lex->et_compile_phase)
+ {
+ switch (lex->et->init_execute_at(YYTHD, $2)) {
+ case EVEX_PARSE_ERROR:
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
+ break;
+ case EVEX_BAD_PARAMS:
+ my_error(ER_EVENT_EXEC_TIME_IN_THE_PAST, MYF(0));
+ YYABORT;
+ break;
+ }
+ }
+ }
+ ;
+
+ev_status: /* empty */
+ | ENABLE_SYM
+ {
+ LEX *lex=Lex;
+ if (!lex->et_compile_phase)
+ lex->et->set_event_status(1);
+ }
+ | DISABLE_SYM
+ {
+ LEX *lex=Lex;
+
+ if (!lex->et_compile_phase)
+ lex->et->set_event_status(0);
+ }
+ ;
+ev_starts: /* empty */
+ | STARTS_SYM expr
+ {
+ LEX *lex= Lex;
+ if (!lex->et_compile_phase)
+ lex->et->init_starts(YYTHD, $2);
+ }
+ ;
+ev_ends: /* empty */
+ | ENDS_SYM expr
+ {
+ LEX *lex= Lex;
+ if (!lex->et_compile_phase)
+ {
+ switch (lex->et->init_ends(YYTHD, $2)) {
+ case EVEX_PARSE_ERROR:
+ yyerror(ER(ER_SYNTAX_ERROR));
+ YYABORT;
+ break;
+ case EVEX_BAD_PARAMS:
+ my_error(ER_EVENT_ENDS_BEFORE_STARTS, MYF(0));
+ YYABORT;
+ break;
+ }
+ }
+ }
+ ;
+ev_on_completion: /* empty */
+ | ON COMPLETION_SYM PRESERVE_SYM
+ {
+ LEX *lex=Lex;
+ if (!lex->et_compile_phase)
+ lex->et->set_on_completion_drop(false);
+ }
+ | ON COMPLETION_SYM NOT_SYM PRESERVE_SYM
+ {
+ LEX *lex=Lex;
+ if (!lex->et_compile_phase)
+ lex->et->set_on_completion_drop(true);
+ }
+ ;
+ev_comment: /* empty */
+ | COMMENT_SYM TEXT_STRING_sys
+ {
+ LEX *lex= Lex;
+ if (!lex->et_compile_phase)
+ {
+ lex->comment= $2;
+ lex->et->init_comment(YYTHD, &$2);
+ }
+ }
+ ;
+
+ev_sql_stmt:
+ {
+ LEX *lex= Lex;
+ sp_head *sp;
+
+ if (!(sp= new sp_head()))
+ YYABORT;
+
+ sp->reset_thd_mem_root(YYTHD);
+ sp->init(lex);
+
+ sp->m_type= TYPE_ENUM_PROCEDURE;
+ lex->sphead= sp;
+
+ bzero((char *)&lex->sp_chistics, sizeof(st_sp_chistics));
+ lex->sphead->m_chistics= &lex->sp_chistics;
+
+ lex->sphead->m_body_begin= lex->ptr;
+ if (!lex->et_compile_phase)
+ lex->et->m_body_begin= lex->ptr;
+ }
+ ev_sql_stmt_inner
+ {
+ LEX *lex=Lex;
+ sp_head *sp= lex->sphead;
+ // return back to the original memory root ASAP
+ sp->init_strings(YYTHD, lex, NULL);
+ sp->restore_thd_mem_root(YYTHD);
+
+ lex->sp_chistics.suid= SP_IS_SUID;//always the definer!
+
+ // Restore flag if it was cleared above
+ if (lex->et->m_old_cmq)
+ YYTHD->client_capabilities |= CLIENT_MULTI_QUERIES;
+
+ if (!lex->et_compile_phase)
+ {
+ lex->et->init_body(YYTHD);
+ lex->et->init_definer(YYTHD);
+ }
+ }
+ ;
+
+ev_sql_stmt_inner:
+ sp_proc_stmt_statement
+ | sp_proc_stmt_return
+ | sp_proc_stmt_if
+ | sp_proc_stmt_case_simple
+ | sp_proc_stmt_case
+ | sp_labeled_control {}
+ | sp_proc_stmt_unlabeled
+ | sp_proc_stmt_leave
+ | sp_proc_stmt_iterate
+ | sp_proc_stmt_label
+ | sp_proc_stmt_goto
+ | sp_proc_stmt_open
+ | sp_proc_stmt_fetch
+ | sp_proc_stmt_close
+ ;
clear_privileges:
/* Nothing */
@@ -1905,6 +2127,28 @@ sp_opt_default:
;
sp_proc_stmt:
+ sp_proc_stmt_statement
+ | sp_proc_stmt_return
+ | sp_proc_stmt_if
+ | sp_proc_stmt_case_simple
+ | sp_proc_stmt_case
+ | sp_labeled_control
+ {}
+ | sp_proc_stmt_unlabeled
+ | sp_proc_stmt_leave
+ | sp_proc_stmt_iterate
+ | sp_proc_stmt_label
+ | sp_proc_stmt_goto
+ | sp_proc_stmt_open
+ | sp_proc_stmt_fetch
+ | sp_proc_stmt_close
+ ;
+
+sp_proc_stmt_if:
+ IF sp_if END IF {}
+ ;
+
+sp_proc_stmt_statement:
{
LEX *lex= Lex;
@@ -1947,7 +2191,10 @@ sp_proc_stmt:
}
sp->restore_lex(YYTHD);
}
- | RETURN_SYM
+ ;
+
+sp_proc_stmt_return:
+ RETURN_SYM
{ Lex->sphead->reset_lex(YYTHD); }
expr
{
@@ -1970,13 +2217,18 @@ sp_proc_stmt:
}
sp->restore_lex(YYTHD);
}
- | IF sp_if END IF {}
- | CASE_SYM WHEN_SYM
+ ;
+
+sp_proc_stmt_case_simple:
+ CASE_SYM WHEN_SYM
{
Lex->sphead->m_flags&= ~sp_head::IN_SIMPLE_CASE;
}
sp_case END CASE_SYM {}
- | CASE_SYM
+ ;
+
+sp_proc_stmt_case:
+ CASE_SYM
{ Lex->sphead->reset_lex(YYTHD); }
expr WHEN_SYM
{
@@ -2000,9 +2252,10 @@ sp_proc_stmt:
{
Lex->spcont->pop_pvar();
}
- | sp_labeled_control
- {}
- | { /* Unlabeled controls get a secret label. */
+ ;
+
+sp_proc_stmt_unlabeled:
+ { /* Unlabeled controls get a secret label. */
LEX *lex= Lex;
lex->spcont->push_label((char *)"", lex->sphead->instructions());
@@ -2013,7 +2266,10 @@ sp_proc_stmt:
lex->sphead->backpatch(lex->spcont->pop_label());
}
- | LEAVE_SYM label_ident
+ ;
+
+sp_proc_stmt_leave:
+ LEAVE_SYM label_ident
{
LEX *lex= Lex;
sp_head *sp = lex->sphead;
@@ -2043,7 +2299,10 @@ sp_proc_stmt:
sp->add_instr(i);
}
}
- | ITERATE_SYM label_ident
+ ;
+
+sp_proc_stmt_iterate:
+ ITERATE_SYM label_ident
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
@@ -2071,7 +2330,10 @@ sp_proc_stmt:
sp->add_instr(i);
}
}
- | LABEL_SYM IDENT
+ ;
+
+sp_proc_stmt_label:
+ LABEL_SYM IDENT
{
#ifdef SP_GOTO
LEX *lex= Lex;
@@ -2096,7 +2358,10 @@ sp_proc_stmt:
YYABORT;
#endif
}
- | GOTO_SYM IDENT
+ ;
+
+sp_proc_stmt_goto:
+ GOTO_SYM IDENT
{
#ifdef SP_GOTO
LEX *lex= Lex;
@@ -2156,7 +2421,10 @@ sp_proc_stmt:
YYABORT;
#endif
}
- | OPEN_SYM ident
+ ;
+
+sp_proc_stmt_open:
+ OPEN_SYM ident
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
@@ -2171,7 +2439,10 @@ sp_proc_stmt:
i= new sp_instr_copen(sp->instructions(), lex->spcont, offset);
sp->add_instr(i);
}
- | FETCH_SYM sp_opt_fetch_noise ident INTO
+ ;
+
+sp_proc_stmt_fetch:
+ FETCH_SYM sp_opt_fetch_noise ident INTO
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
@@ -2188,7 +2459,10 @@ sp_proc_stmt:
}
sp_fetch_list
{ }
- | CLOSE_SYM ident
+ ;
+
+sp_proc_stmt_close:
+ CLOSE_SYM ident
{
LEX *lex= Lex;
sp_head *sp= lex->sphead;
@@ -3913,8 +4187,64 @@ alter:
}
view_list_opt AS view_select view_check_option
{}
- ;
+ | ALTER EVENT_SYM sp_name
+ {
+ LEX *lex=Lex;
+ event_timed *et;
+
+ if (lex->et)
+ {
+ // ToDo Andrey : Change the error message
+ my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "EVENT");
+ YYABORT;
+ }
+ lex->spname= 0;//defensive
+
+ et= new event_timed();// implicitly calls event_timed::init()
+ lex->et = et;
+ et->init_name(YYTHD, $3);
+
+ /*
+ We have to turn of CLIENT_MULTI_QUERIES while parsing a
+ stored procedure, otherwise yylex will chop it into pieces
+ at each ';'.
+ */
+ et->m_old_cmq= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES;
+ YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES;
+
+ /*
+ defensive. in sql_parse.cc it is checked whether is not null
+ and then deleted
+ */
+ lex->sphead= 0;
+ }
+ ev_on_schedule
+ ev_rename_to
+ ev_on_completion
+ ev_status
+ ev_comment
+ ev_opt_sql_stmt
+ {
+ LEX *lex=Lex;
+ lex->sql_command= SQLCOM_ALTER_EVENT;
+ }
+ ;
+
+ev_on_schedule: /* empty */
+ | ON SCHEDULE_SYM ev_schedule_time;
+
+ev_opt_sql_stmt: /* empty*/
+ | DO_SYM ev_sql_stmt;
+ev_rename_to: /* empty */
+ | RENAME TO_SYM sp_name
+ {
+ LEX *lex=Lex;
+ lex->spname= $3; //use lex's spname to hold the new name
+ //the original name is in the event_timed object
+ }
+ ;
+
ident_or_empty:
/* empty */ { $$= 0; }
| ident { $$= $1.str; };
@@ -6620,7 +6950,26 @@ drop:
lex->sql_command= SQLCOM_DROP_TRIGGER;
lex->spname= $3;
}
- ;
+ | DROP EVENT_SYM if_exists sp_name
+ {
+ LEX *lex=Lex;
+ event_timed *et;
+
+ if (lex->et)
+ {
+ // ToDo Andrey : Change the error message
+ my_error(ER_SP_NO_RECURSIVE_CREATE, MYF(0), "EVENT");
+ YYABORT;
+ }
+
+ et= new event_timed;
+ lex->et = et;
+ et->init_name(YYTHD, $4);
+
+ lex->sql_command = SQLCOM_DROP_EVENT;
+ lex->drop_if_exists= $3;
+ }
+ ;
table_list:
table_name
@@ -7272,7 +7621,14 @@ show_param:
Lex->spname= $3;
#endif
}
- ;
+ | CREATE EVENT_SYM sp_name
+ {
+ LEX *lex= Lex;
+
+ lex->sql_command = SQLCOM_SHOW_CREATE_EVENT;
+ lex->spname= $3;
+ };
+ ;
show_engine_param:
STATUS_SYM
@@ -8159,6 +8515,7 @@ keyword_sp:
| AGGREGATE_SYM {}
| ALGORITHM_SYM {}
| ANY_SYM {}
+ | AT_SYM {}
| AUTO_INC {}
| AVG_ROW_LENGTH {}
| AVG_SYM {}
@@ -8179,6 +8536,7 @@ keyword_sp:
| COLUMNS {}
| COMMITTED_SYM {}
| COMPACT_SYM {}
+ | COMPLETION_SYM {}
| COMPRESSED_SYM {}
| CONCURRENT {}
| CONSISTENT_SYM {}
@@ -8195,12 +8553,15 @@ keyword_sp:
| DUMPFILE {}
| DUPLICATE_SYM {}
| DYNAMIC_SYM {}
+ | ENDS_SYM {}
| ENUM {}
| ENGINE_SYM {}
| ENGINES_SYM {}
| ERRORS {}
| ESCAPE_SYM {}
+ | EVENT_SYM {}
| EVENTS_SYM {}
+ | EVERY_SYM {}
| EXPANSION_SYM {}
| EXTENDED_SYM {}
| FAST_SYM {}
@@ -8293,6 +8654,7 @@ keyword_sp:
| PHASE_SYM {}
| POINT_SYM {}
| POLYGON {}
+ | PRESERVE_SYM {}
| PREV_SYM {}
| PRIVILEGES {}
| PROCESS {}
@@ -8322,6 +8684,7 @@ keyword_sp:
| ROW_FORMAT_SYM {}
| ROW_SYM {}
| RTREE_SYM {}
+ | SCHEDULE_SYM {}
| SECOND_SYM {}
| SERIAL_SYM {}
| SERIALIZABLE_SYM {}
@@ -8335,6 +8698,7 @@ keyword_sp:
| SQL_BUFFER_RESULT {}
| SQL_NO_CACHE_SYM {}
| SQL_THREAD {}
+ | STARTS_SYM {}
| STATUS_SYM {}
| STORAGE_SYM {}
| STRING_SYM {}
@@ -9061,6 +9425,7 @@ object_privilege:
| CREATE ROUTINE_SYM { Lex->grant |= CREATE_PROC_ACL; }
| ALTER ROUTINE_SYM { Lex->grant |= ALTER_PROC_ACL; }
| CREATE USER { Lex->grant |= CREATE_USER_ACL; }
+ | EVENT_SYM { Lex->grant |= EVENT_ACL;}
;
diff --git a/sql/table.cc b/sql/table.cc
index aeccab78211..d5a432306f7 100644
--- a/sql/table.cc
+++ b/sql/table.cc
@@ -282,7 +282,8 @@ int open_table_def(THD *thd, TABLE_SHARE *share, uint db_flags)
*/
if (share->db.length == 5 &&
!my_strcasecmp(system_charset_info, share->db.str, "mysql") &&
- !my_strcasecmp(system_charset_info, share->table_name.str, "proc"))
+ (!my_strcasecmp(system_charset_info, share->table_name.str, "proc") ||
+ !my_strcasecmp(system_charset_info, share->table_name.str, "event")))
share->system_table= 1;
error_given= 1;
}
diff --git a/sql/tztime.cc b/sql/tztime.cc
index eba2f8f4a7b..50c3cf1fe4f 100644
--- a/sql/tztime.cc
+++ b/sql/tztime.cc
@@ -807,6 +807,18 @@ sec_since_epoch(int year, int mon, int mday, int hour, int min ,int sec)
}
+ /*
+ Works like sec_since_epoch but expects TIME structure as parameter.
+*/
+
+my_time_t
+sec_since_epoch_TIME(TIME *t)
+{
+ return sec_since_epoch(t->year, t->month, t->day,
+ t->hour, t->minute, t->second);
+}
+
+
/*
Converts local time in broken down TIME representation to my_time_t
representation.
diff --git a/sql/tztime.h b/sql/tztime.h
index a168fe4fb73..312451d84e0 100644
--- a/sql/tztime.h
+++ b/sql/tztime.h
@@ -64,6 +64,7 @@ extern Time_zone * my_tz_find(const String *name, TABLE_LIST *tz_tables);
extern Time_zone * my_tz_find_with_opening_tz_tables(THD *thd, const String *name);
extern my_bool my_tz_init(THD *org_thd, const char *default_tzname, my_bool bootstrap);
extern void my_tz_free();
+my_time_t sec_since_epoch_TIME(TIME *t);
extern TABLE_LIST fake_time_zone_tables_list;