diff options
-rwxr-xr-x | BUILD/SETUP.sh | 2 | ||||
-rw-r--r-- | include/my_sys.h | 1 | ||||
-rw-r--r-- | libmysqld/Makefile.am | 4 | ||||
-rw-r--r-- | mysys/array.c | 25 | ||||
-rw-r--r-- | sql/Makefile.am | 4 | ||||
-rw-r--r-- | sql/lex.h | 8 | ||||
-rw-r--r-- | sql/mysqld.cc | 12 | ||||
-rw-r--r-- | sql/set_var.cc | 4 | ||||
-rw-r--r-- | sql/share/errmsg.txt | 16 | ||||
-rw-r--r-- | sql/sp.cc | 88 | ||||
-rw-r--r-- | sql/sp.h | 12 | ||||
-rw-r--r-- | sql/sql_acl.cc | 4 | ||||
-rw-r--r-- | sql/sql_acl.h | 3 | ||||
-rw-r--r-- | sql/sql_lex.cc | 4 | ||||
-rw-r--r-- | sql/sql_lex.h | 7 | ||||
-rw-r--r-- | sql/sql_parse.cc | 128 | ||||
-rw-r--r-- | sql/sql_show.cc | 5 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 401 | ||||
-rw-r--r-- | sql/table.cc | 3 | ||||
-rw-r--r-- | sql/tztime.cc | 12 | ||||
-rw-r--r-- | sql/tztime.h | 1 |
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, ¬_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; @@ -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; |