diff options
author | unknown <andrey@lmy004.> | 2006-01-30 14:28:48 +0100 |
---|---|---|
committer | unknown <andrey@lmy004.> | 2006-01-30 14:28:48 +0100 |
commit | 2272e140fd1490772fa9660ece4ea91eed26cee7 (patch) | |
tree | 8ef0243df685fd27f6f69d8bcff5e5743c6a0648 | |
parent | 799129e254fca5df0fddc910c371acce7fb666dc (diff) | |
parent | c3542cebf9c775241652ef8f0a4ed7dd788683d7 (diff) | |
download | mariadb-git-2272e140fd1490772fa9660ece4ea91eed26cee7.tar.gz |
post-commit merge
mysql-test/lib/init_db.sql:
Auto merged
scripts/mysql_create_system_tables.sh:
Auto merged
scripts/mysql_fix_privilege_tables.sql:
Auto merged
sql/event.cc:
Auto merged
sql/event.h:
Auto merged
sql/event_executor.cc:
Auto merged
sql/event_priv.h:
Auto merged
sql/event_timed.cc:
Auto merged
sql/mysqld.cc:
Auto merged
sql/sql_lex.h:
Auto merged
sql/sql_parse.cc:
Auto merged
sql/sql_yacc.yy:
Auto merged
mysql-test/r/events.result:
manual merge
mysql-test/r/system_mysql_db.result:
manual merge
mysql-test/t/events.test:
manual merge
-rw-r--r-- | mysql-test/lib/init_db.sql | 2 | ||||
-rw-r--r-- | mysql-test/r/events.result | 161 | ||||
-rw-r--r-- | mysql-test/r/information_schema.result | 13 | ||||
-rw-r--r-- | mysql-test/r/information_schema_db.result | 1 | ||||
-rw-r--r-- | mysql-test/t/events.test | 76 | ||||
-rw-r--r-- | scripts/mysql_create_system_tables.sh | 2 | ||||
-rw-r--r-- | scripts/mysql_fix_privilege_tables.sql | 2 | ||||
-rw-r--r-- | sql/event.cc | 63 | ||||
-rw-r--r-- | sql/event.h | 33 | ||||
-rw-r--r-- | sql/event_executor.cc | 5 | ||||
-rw-r--r-- | sql/event_priv.h | 27 | ||||
-rw-r--r-- | sql/event_timed.cc | 27 | ||||
-rw-r--r-- | sql/mysqld.cc | 1 | ||||
-rw-r--r-- | sql/sql_lex.h | 2 | ||||
-rw-r--r-- | sql/sql_parse.cc | 7 | ||||
-rw-r--r-- | sql/sql_show.cc | 292 | ||||
-rw-r--r-- | sql/sql_yacc.yy | 31 | ||||
-rw-r--r-- | sql/table.h | 1 |
18 files changed, 674 insertions, 72 deletions
diff --git a/mysql-test/lib/init_db.sql b/mysql-test/lib/init_db.sql index b07af136c23..0c287aa092a 100644 --- a/mysql-test/lib/init_db.sql +++ b/mysql-test/lib/init_db.sql @@ -596,7 +596,7 @@ CREATE TABLE event ( status ENUM('ENABLED','DISABLED') NOT NULL default 'ENABLED', on_completion ENUM('DROP','PRESERVE') NOT NULL default 'DROP', comment char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', - PRIMARY KEY (db,name) + PRIMARY KEY (definer, db, name) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT 'Events'; CREATE DATABASE IF NOT EXISTS cluster_replication; diff --git a/mysql-test/r/events.result b/mysql-test/r/events.result index 38c2d902ec1..df03cd4ec84 100644 --- a/mysql-test/r/events.result +++ b/mysql-test/r/events.result @@ -57,4 +57,165 @@ set event_scheduler=0; ERROR HY000: Variable 'event_scheduler' is a GLOBAL variable and should be set with SET GLOBAL set global event_scheduler=2; ERROR 42000: Variable 'event_scheduler' can't be set to the value of '2' +create event one_event on schedule every 10 second do select 123; +SHOW EVENTS; +Db Name Definer Type Execute at Interval value Interval field Starts Ends Status +events_test one_event root@localhost RECURRING NULL 10 INTERVAL_SECOND # # ENABLED +SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT from information_schema.events; +EVENT_CATALOG EVENT_SCHEMA EVENT_NAME DEFINER EVENT_BODY EVENT_TYPE EXECUTE_AT INTERVAL_VALUE INTERVAL_FIELD STATUS ON_COMPLETION EVENT_COMMENT +NULL events_test one_event root@localhost select 123 RECURRING NULL 10 INTERVAL_SECOND ENABLED NOT PRESERVE +CREATE DATABASE events_test2; +CREATE USER ev_test@localhost; +GRANT ALL ON events_test.* to ev_test@localhost; +GRANT ALL on events_test2.* to ev_test@localhost; +REVOKE EVENT ON events_test2.* FROM ev_test@localhost; +REVOKE PROCESS on *.* from ev_test@localhost; +select "NEW CONNECTION"; +NEW CONNECTION +NEW CONNECTION +SELECT USER(), DATABASE(); +USER() DATABASE() +ev_test@localhost events_test2 +SHOW GRANTS; +Grants for ev_test@localhost +GRANT USAGE ON *.* TO 'ev_test'@'localhost' +GRANT ALL PRIVILEGES ON `events_test`.* TO 'ev_test'@'localhost' +GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, ALTER, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE ON `events_test2`.* TO 'ev_test'@'localhost' +select "Here comes an error:"; +Here comes an error: +Here comes an error: +SHOW EVENTS; +ERROR 42000: Access denied for user 'ev_test'@'localhost' to database 'events_test2' +USE events_test; +select "Now the list should be empty:"; +Now the list should be empty: +Now the list should be empty: +SHOW EVENTS; +Db Name Definer Type Execute at Interval value Interval field Starts Ends Status +select concat("Let's create some new events from the name of ",user()); +concat("Let's create some new events from the name of ",user()) +Let's create some new events from the name of ev_test@localhost +create event one_event on schedule every 20 second do select 123; +create event two_event on schedule every 20 second on completion not preserve comment "two event" do select 123; +create event three_event on schedule every 20 second on completion preserve comment "three event" do select 123; +select "Now we should see 3 events:"; +Now we should see 3 events: +Now we should see 3 events: +SHOW EVENTS; +Db Name Definer Type Execute at Interval value Interval field Starts Ends Status +events_test one_event ev_test@localhost RECURRING NULL 20 INTERVAL_SECOND # # ENABLED +events_test three_event ev_test@localhost RECURRING NULL 20 INTERVAL_SECOND # # ENABLED +events_test two_event ev_test@localhost RECURRING NULL 20 INTERVAL_SECOND # # ENABLED +select "This should show us only 3 events:"; +This should show us only 3 events: +This should show us only 3 events: +SHOW FULL EVENTS; +Db Name Definer Type Execute at Interval value Interval field Starts Ends Status +events_test one_event ev_test@localhost RECURRING NULL 20 INTERVAL_SECOND # # ENABLED +events_test three_event ev_test@localhost RECURRING NULL 20 INTERVAL_SECOND # # ENABLED +events_test two_event ev_test@localhost RECURRING NULL 20 INTERVAL_SECOND # # ENABLED +select "This should show us only 2 events:"; +This should show us only 2 events: +This should show us only 2 events: +SHOW FULL EVENTS LIKE 't%event'; +Db Name Definer Type Execute at Interval value Interval field Starts Ends Status +events_test three_event ev_test@localhost RECURRING NULL 20 INTERVAL_SECOND # # ENABLED +events_test two_event ev_test@localhost RECURRING NULL 20 INTERVAL_SECOND # # ENABLED +select "This should show us no events:"; +This should show us no events: +This should show us no events: +SHOW FULL EVENTS FROM test LIKE '%'; +Db Name Definer Type Execute at Interval value Interval field Starts Ends Status +DROP DATABASE events_test2; +select "should see 1 event:"; +should see 1 event: +should see 1 event: +SHOW EVENTS; +Db Name Definer Type Execute at Interval value Interval field Starts Ends Status +events_test one_event root@localhost RECURRING NULL 10 INTERVAL_SECOND # # ENABLED +select "we should see 4 events now:"; +we should see 4 events now: +we should see 4 events now: +SHOW FULL EVENTS; +Db Name Definer Type Execute at Interval value Interval field Starts Ends Status +events_test one_event ev_test@localhost RECURRING NULL 20 INTERVAL_SECOND # # ENABLED +events_test three_event ev_test@localhost RECURRING NULL 20 INTERVAL_SECOND # # ENABLED +events_test two_event ev_test@localhost RECURRING NULL 20 INTERVAL_SECOND # # ENABLED +events_test one_event root@localhost RECURRING NULL 10 INTERVAL_SECOND # # ENABLED +SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT from information_schema.events; +EVENT_CATALOG EVENT_SCHEMA EVENT_NAME DEFINER EVENT_BODY EVENT_TYPE EXECUTE_AT INTERVAL_VALUE INTERVAL_FIELD STATUS ON_COMPLETION EVENT_COMMENT +NULL events_test one_event ev_test@localhost select 123 RECURRING NULL 20 INTERVAL_SECOND ENABLED NOT PRESERVE +NULL events_test three_event ev_test@localhost select 123 RECURRING NULL 20 INTERVAL_SECOND ENABLED PRESERVE three event +NULL events_test two_event ev_test@localhost select 123 RECURRING NULL 20 INTERVAL_SECOND ENABLED NOT PRESERVE two event +NULL events_test one_event root@localhost select 123 RECURRING NULL 10 INTERVAL_SECOND ENABLED NOT PRESERVE +drop event one_event; +drop event two_event; +drop event three_event; +drop user ev_test@localhost; +drop event one_event; +set global event_scheduler=0; +select count(*) from mysql.event; +count(*) +0 +select get_lock("test_lock1", 20); +get_lock("test_lock1", 20) +1 +create event закачка on schedule every 10 hour do select get_lock("test_lock1", 20); +select count(*) from mysql.event; +count(*) +1 +select release_lock("test_lock1"); +release_lock("test_lock1") +1 +drop event закачка; +select count(*) from mysql.event; +count(*) +0 +set global event_scheduler=1; +select get_lock("test_lock2", 20); +get_lock("test_lock2", 20) +1 +create event закачка on schedule every 10 hour do select get_lock("test_lock2", 20); +select sleep(2); +sleep(2) +0 +select release_lock("test_lock2"); +release_lock("test_lock2") +1 +drop event закачка; +set global event_scheduler=1; +select get_lock("test_lock2_1", 20); +get_lock("test_lock2_1", 20) +1 +create event закачка21 on schedule every 10 hour do select get_lock("test_lock2_1", 20); +select sleep(2); +sleep(2) +0 +set global event_scheduler=0; +select sleep(2); +sleep(2) +0 +select release_lock("test_lock2_1"); +release_lock("test_lock2_1") +1 +select sleep(2); +sleep(2) +0 +drop event закачка21; +set global event_scheduler=1; +select get_lock("test_lock3", 20); +get_lock("test_lock3", 20) +1 +create event закачка on schedule every 10 hour do select get_lock("test_lock3", 20); +select sleep(2); +sleep(2) +0 +drop event закачка; +select release_lock("test_lock3"); +release_lock("test_lock3") +1 +set global event_scheduler=0; +select sleep(2); +sleep(2) +0 drop database events_test; diff --git a/mysql-test/r/information_schema.result b/mysql-test/r/information_schema.result index 8778ded244f..40706fd9c55 100644 --- a/mysql-test/r/information_schema.result +++ b/mysql-test/r/information_schema.result @@ -44,6 +44,7 @@ COLLATION_CHARACTER_SET_APPLICABILITY COLUMNS COLUMN_PRIVILEGES ENGINES +EVENTS KEY_COLUMN_USAGE PARTITIONS PLUGINS @@ -734,7 +735,7 @@ CREATE TABLE t_crashme ( f1 BIGINT); CREATE VIEW a1 (t_CRASHME) AS SELECT f1 FROM t_crashme GROUP BY f1; CREATE VIEW a2 AS SELECT t_CRASHME FROM a1; count(*) -109 +110 drop view a2, a1; drop table t_crashme; select table_schema,table_name, column_name from @@ -742,6 +743,8 @@ information_schema.columns where data_type = 'longtext'; table_schema table_name column_name information_schema COLUMNS COLUMN_TYPE +information_schema EVENTS EVENT_BODY +information_schema EVENTS SQL_MODE information_schema PARTITIONS PARTITION_EXPRESSION information_schema PARTITIONS SUBPARTITION_EXPRESSION information_schema PARTITIONS PARTITION_DESCRIPTION @@ -756,6 +759,12 @@ information_schema VIEWS VIEW_DEFINITION select table_name, column_name, data_type from information_schema.columns where data_type = 'datetime'; table_name column_name data_type +EVENTS EXECUTE_AT datetime +EVENTS STARTS datetime +EVENTS ENDS datetime +EVENTS CREATED datetime +EVENTS LAST_ALTERED datetime +EVENTS LAST_EXECUTED datetime PARTITIONS CREATE_TIME datetime PARTITIONS UPDATE_TIME datetime PARTITIONS CHECK_TIME datetime @@ -817,7 +826,7 @@ flush privileges; SELECT table_schema, count(*) FROM information_schema.TABLES GROUP BY TABLE_SCHEMA; table_schema count(*) cluster_replication 1 -information_schema 19 +information_schema 20 mysql 21 create table t1 (i int, j int); create trigger trg1 before insert on t1 for each row diff --git a/mysql-test/r/information_schema_db.result b/mysql-test/r/information_schema_db.result index 7832e34dfd1..1ad996dedd5 100644 --- a/mysql-test/r/information_schema_db.result +++ b/mysql-test/r/information_schema_db.result @@ -7,6 +7,7 @@ COLLATION_CHARACTER_SET_APPLICABILITY COLUMNS COLUMN_PRIVILEGES ENGINES +EVENTS KEY_COLUMN_USAGE PARTITIONS PLUGINS diff --git a/mysql-test/t/events.test b/mysql-test/t/events.test index c92e247ef7f..54dec5429b0 100644 --- a/mysql-test/t/events.test +++ b/mysql-test/t/events.test @@ -33,6 +33,82 @@ select count(*) from t_event3; drop event event3; drop table t_event3; +# +#INFORMATION_SCHEMA.EVENTS test begin +# +create event one_event on schedule every 10 second do select 123; +--replace_column 8 # 9 # +SHOW EVENTS; +SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT from information_schema.events; +CREATE DATABASE events_test2; +CREATE USER ev_test@localhost; +GRANT ALL ON events_test.* to ev_test@localhost; +GRANT ALL on events_test2.* to ev_test@localhost; +REVOKE EVENT ON events_test2.* FROM ev_test@localhost; +REVOKE PROCESS on *.* from ev_test@localhost; +#now we are on con1 +connect (ev_con1,localhost,ev_test,,events_test2); +select "NEW CONNECTION"; +SELECT USER(), DATABASE(); +SHOW GRANTS; + +select "Here comes an error:"; +#NO EVENT_ACL on events_test2 +--error 1044 +SHOW EVENTS; +USE events_test; + +select "Now the list should be empty:"; +--replace_column 8 # 9 # +SHOW EVENTS; +#now create an event with the same name but we are different user +select concat("Let's create some new events from the name of ",user()); +create event one_event on schedule every 20 second do select 123; +create event two_event on schedule every 20 second on completion not preserve comment "two event" do select 123; +create event three_event on schedule every 20 second on completion preserve comment "three event" do select 123; + +select "Now we should see 3 events:"; +--replace_column 8 # 9 # +SHOW EVENTS; + +select "This should show us only 3 events:"; +--replace_column 8 # 9 # +SHOW FULL EVENTS; + +select "This should show us only 2 events:"; +--replace_column 8 # 9 # +SHOW FULL EVENTS LIKE 't%event'; + +select "This should show us no events:"; +--replace_column 8 # 9 # +SHOW FULL EVENTS FROM test LIKE '%'; +#ok, we are back +connection default; +DROP DATABASE events_test2; + +select "should see 1 event:"; +--replace_column 8 # 9 # +SHOW EVENTS; + +select "we should see 4 events now:"; +--replace_column 8 # 9 # +SHOW FULL EVENTS; +SELECT EVENT_CATALOG, EVENT_SCHEMA, EVENT_NAME, DEFINER, EVENT_BODY, EVENT_TYPE, EXECUTE_AT, INTERVAL_VALUE, INTERVAL_FIELD, STATUS,ON_COMPLETION, EVENT_COMMENT from information_schema.events; + +connection ev_con1; +drop event one_event; +drop event two_event; +drop event three_event; +disconnect ev_con1; +connection default; +drop user ev_test@localhost; +drop event one_event; +# +##INFORMATION_SCHEMA.EVENTS test end +# + + + create event e_26 on schedule at '2017-01-01 00:00:00' disable do set @a = 5; select db, name, body, definer, convert_tz(execute_at, 'UTC', 'SYSTEM'), on_completion from mysql.event; diff --git a/scripts/mysql_create_system_tables.sh b/scripts/mysql_create_system_tables.sh index 2822cef18ac..385e04a4cc2 100644 --- a/scripts/mysql_create_system_tables.sh +++ b/scripts/mysql_create_system_tables.sh @@ -792,7 +792,7 @@ then c_ev="$c_ev status ENUM('ENABLED','DISABLED') NOT NULL default 'ENABLED'," c_ev="$c_ev on_completion ENUM('DROP','PRESERVE') NOT NULL default 'DROP'," c_ev="$c_ev comment char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default ''," - c_ev="$c_ev PRIMARY KEY (db,name)" + c_ev="$c_ev PRIMARY KEY (definer, db, name)" c_ev="$c_ev ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT 'Events';" fi diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql index 360e8534773..c8014127085 100644 --- a/scripts/mysql_fix_privilege_tables.sql +++ b/scripts/mysql_fix_privilege_tables.sql @@ -600,4 +600,6 @@ CREATE TABLE event ( ALTER TABLE user add Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL AFTER Create_user_priv; ALTER TABLE db add Event_priv enum('N','Y') character set utf8 DEFAULT 'N' NOT NULL; +ALTER TABLE event DROP PRIMARY KEY; +ALTER TABLE event ADD PRIMARY KEY(definer, db, name); diff --git a/sql/event.cc b/sql/event.cc index 4a6fff581a3..abca622835a 100644 --- a/sql/event.cc +++ b/sql/event.cc @@ -77,7 +77,7 @@ evex_queue_init(EVEX_QUEUE_TYPE *queue) } -static + int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs) { return cs->coll->strnncollsp(cs, (unsigned char *) s.str,s.length, @@ -182,7 +182,9 @@ evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table) int evex_db_find_event_aux(THD *thd, const LEX_STRING dbname, - const LEX_STRING ev_name, TABLE *table) + const LEX_STRING ev_name, + const LEX_STRING user_name, + TABLE *table) { byte key[MAX_KEY_LENGTH]; DBUG_ENTER("evex_db_find_event_aux"); @@ -196,11 +198,17 @@ evex_db_find_event_aux(THD *thd, const LEX_STRING dbname, same fields. */ if (dbname.length > table->field[EVEX_FIELD_DB]->field_length || - ev_name.length > table->field[EVEX_FIELD_NAME]->field_length) + ev_name.length > table->field[EVEX_FIELD_NAME]->field_length || + user_name.length > table->field[EVEX_FIELD_DEFINER]->field_length) + DBUG_RETURN(EVEX_KEY_NOT_FOUND); - table->field[0]->store(dbname.str, dbname.length, &my_charset_bin); - table->field[1]->store(ev_name.str, ev_name.length, &my_charset_bin); + table->field[EVEX_FIELD_DB]->store(dbname.str, dbname.length, &my_charset_bin); + table->field[EVEX_FIELD_NAME]->store(ev_name.str, ev_name.length, + &my_charset_bin); + table->field[EVEX_FIELD_DEFINER]->store(user_name.str, user_name.length, + &my_charset_bin); + key_copy(key, table->record[0], table->key_info, table->key_info->key_length); if (table->file->index_read_idx(table->record[0], 0, key, @@ -290,10 +298,15 @@ evex_fill_row(THD *thd, TABLE *table, event_timed *et, my_bool is_update) from 1. Thus +1 offset is needed! */ table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->store((longlong)et->interval+1); + + table->field[EVEX_FIELD_EXECUTE_AT]->set_null(); } else if (et->execute_at.year) { // fix_fields already called in init_execute_at + table->field[EVEX_FIELD_INTERVAL_EXPR]->set_null(); + table->field[EVEX_FIELD_TRANSIENT_INTERVAL]->set_null(); + table->field[EVEX_FIELD_EXECUTE_AT]->set_notnull(); table->field[EVEX_FIELD_EXECUTE_AT]->store_time(&et->execute_at, MYSQL_TIMESTAMP_DATETIME); @@ -358,9 +371,9 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not, my_error(ER_EVENT_OPEN_TABLE_FAILED, MYF(0)); goto err; } - + DBUG_PRINT("info", ("check existance of an event with the same name")); - if (!evex_db_find_event_aux(thd, et->dbname, et->name, table)) + if (!evex_db_find_event_aux(thd, et->dbname, et->name, et->definer, table)) { if (create_if_not) { @@ -410,10 +423,9 @@ db_create_event(THD *thd, event_timed *et, my_bool create_if_not, goto err; } - strxmov(definer, et->definer_user.str, "@", et->definer_host.str, NullS); - if ((ret=table->field[EVEX_FIELD_DEFINER]-> - store(definer, et->definer_user.length + 1 + et->definer_host.length, - system_charset_info))) + if ((ret=table->field[EVEX_FIELD_DEFINER]->store(et->definer.str, + et->definer.length, + system_charset_info))) { my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret); goto err; @@ -476,7 +488,9 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name) TABLE *table; int ret= EVEX_OPEN_TABLE_FAILED; DBUG_ENTER("db_update_event"); + DBUG_PRINT("enter", ("dbname: %.*s", et->dbname.length, et->dbname.str)); DBUG_PRINT("enter", ("name: %.*s", et->name.length, et->name.str)); + DBUG_PRINT("enter", ("user: %.*s", et->name.length, et->name.str)); if (new_name) DBUG_PRINT("enter", ("rename to: %.*s", new_name->m_name.length, new_name->m_name.str)); @@ -497,7 +511,8 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name) goto err; } - if (!evex_db_find_event_aux(thd, new_name->m_db, new_name->m_name, table)) + if (!evex_db_find_event_aux(thd, new_name->m_db, new_name->m_name, + et->definer, table)) { my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->m_name.str); goto err; @@ -510,7 +525,7 @@ db_update_event(THD *thd, event_timed *et, sp_name *new_name) row (copied into record[1] later */ if (EVEX_KEY_NOT_FOUND == evex_db_find_event_aux(thd, et->dbname, et->name, - table)) + et->definer, table)) { my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), et->name.str); goto err; @@ -559,6 +574,7 @@ err: db_find_event() thd THD name the name of the event to find + definer who owns the event ett event's data if event is found tbl TABLE object to use when not NULL @@ -568,11 +584,11 @@ err: */ static int -db_find_event(THD *thd, sp_name *name, event_timed **ett, TABLE *tbl) +db_find_event(THD *thd, sp_name *name, LEX_STRING definer, event_timed **ett, + TABLE *tbl) { TABLE *table; int ret; - const char *definer; char *ptr; event_timed *et; DBUG_ENTER("db_find_event"); @@ -587,7 +603,8 @@ db_find_event(THD *thd, sp_name *name, event_timed **ett, TABLE *tbl) goto done; } - if ((ret= evex_db_find_event_aux(thd, name->m_db, name->m_name, table))) + if ((ret= evex_db_find_event_aux(thd, name->m_db, name->m_name, definer, + table))) { my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name->m_name.str); goto done; @@ -628,6 +645,7 @@ done: evex_load_and_compile_event() thd THD spn the name of the event to alter + definer who is the owner use_lock whether to obtain a lock on LOCK_event_arrays or not RETURN VALUE @@ -637,7 +655,8 @@ done: */ static int -evex_load_and_compile_event(THD * thd, sp_name *spn, bool use_lock) +evex_load_and_compile_event(THD * thd, sp_name *spn, LEX_STRING definer, + bool use_lock) { int ret= 0; MEM_ROOT *tmp_mem_root; @@ -652,7 +671,7 @@ evex_load_and_compile_event(THD * thd, sp_name *spn, bool use_lock) thd->reset_n_backup_open_tables_state(&backup); // no need to use my_error() here because db_find_event() has done it - if ((ret= db_find_event(thd, spn, &ett, NULL))) + if ((ret= db_find_event(thd, spn, definer, &ett, NULL))) goto done; thd->restore_backup_open_tables_state(&backup); @@ -773,7 +792,7 @@ evex_create_event(THD *thd, event_timed *et, uint create_options, if (evex_is_running && et->status == MYSQL_EVENT_ENABLED) { sp_name spn(et->dbname, et->name); - ret= evex_load_and_compile_event(thd, &spn, true); + ret= evex_load_and_compile_event(thd, &spn, et->definer, true); } VOID(pthread_mutex_unlock(&LOCK_evex_running)); @@ -826,11 +845,11 @@ evex_update_event(THD *thd, event_timed *et, sp_name *new_name, if (et->status == MYSQL_EVENT_ENABLED) { if (new_name) - ret= evex_load_and_compile_event(thd, new_name, false); + ret= evex_load_and_compile_event(thd, new_name, et->definer, false); else { sp_name spn(et->dbname, et->name); - ret= evex_load_and_compile_event(thd, &spn, false); + ret= evex_load_and_compile_event(thd, &spn, et->definer, false); } if (ret == EVEX_COMPILE_ERROR) my_error(ER_EVENT_COMPILE_ERROR, MYF(0)); @@ -868,7 +887,7 @@ evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists, goto done; } - if (!(ret= evex_db_find_event_aux(thd, et->dbname, et->name, table))) + if (!(ret= evex_db_find_event_aux(thd, et->dbname,et->name,et->definer,table))) { if ((ret= table->file->ha_delete_row(table->record[0]))) { diff --git a/sql/event.h b/sql/event.h index 80629fa0a70..6ee9cea25ac 100644 --- a/sql/event.h +++ b/sql/event.h @@ -54,6 +54,25 @@ enum enum_event_status MYSQL_EVENT_DISABLED }; +enum evex_table_field +{ + EVEX_FIELD_DB = 0, + EVEX_FIELD_NAME, + EVEX_FIELD_BODY, + EVEX_FIELD_DEFINER, + EVEX_FIELD_EXECUTE_AT, + EVEX_FIELD_INTERVAL_EXPR, + EVEX_FIELD_TRANSIENT_INTERVAL, + EVEX_FIELD_CREATED, + EVEX_FIELD_MODIFIED, + EVEX_FIELD_LAST_EXECUTED, + EVEX_FIELD_STARTS, + EVEX_FIELD_ENDS, + EVEX_FIELD_STATUS, + EVEX_FIELD_ON_COMPLETION, + EVEX_FIELD_COMMENT, + EVEX_FIELD_COUNT /* a cool trick to count the number of fields :) */ +} ; class event_timed { @@ -64,9 +83,10 @@ class event_timed bool status_changed; bool last_executed_changed; - TIME last_executed; public: + TIME last_executed; + LEX_STRING dbname; LEX_STRING name; LEX_STRING body; @@ -83,8 +103,8 @@ public: longlong expression; interval_type interval; - longlong created; - longlong modified; + ulonglong created; + ulonglong modified; enum enum_event_on_completion on_completion; enum enum_event_status status; sp_head *sphead; @@ -197,6 +217,10 @@ int evex_drop_event(THD *thd, event_timed *et, bool drop_if_exists, uint *rows_affected); +int +evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table); + +int sortcmp_lex_string(LEX_STRING s, LEX_STRING t, CHARSET_INFO *cs); int init_events(); @@ -210,6 +234,7 @@ int event_timed_compare(event_timed **a, event_timed **b); + /* CREATE TABLE event ( db char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', @@ -233,7 +258,7 @@ CREATE TABLE event ( status ENUM('ENABLED','DISABLED') NOT NULL default 'ENABLED', on_completion ENUM('DROP','PRESERVE') NOT NULL default 'DROP', comment varchar(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', - PRIMARY KEY (db,name) + PRIMARY KEY (definer,db,name) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT 'Events'; */ diff --git a/sql/event_executor.cc b/sql/event_executor.cc index 4eb92f9e430..dbbff2a8c58 100644 --- a/sql/event_executor.cc +++ b/sql/event_executor.cc @@ -348,7 +348,8 @@ event_executor_main(void *arg) TIME_to_ulonglong_datetime(&et->execute_at))); et->update_fields(thd); - DBUG_PRINT("info", (" Spawning a thread %d", ++iter_num)); + ++iter_num; + DBUG_PRINT("info", (" Spawning a thread %d", iter_num)); #ifndef DBUG_FAULTY_THR if (pthread_create(&th, NULL, event_executor_worker, (void*)et)) { @@ -461,7 +462,7 @@ event_executor_worker(void *event_void) thd->mem_root= &worker_mem_root; pthread_detach(pthread_self()); - + if (init_event_thread(thd)) goto err; diff --git a/sql/event_priv.h b/sql/event_priv.h index 42c60dd391d..7d1cdbcd264 100644 --- a/sql/event_priv.h +++ b/sql/event_priv.h @@ -24,26 +24,6 @@ #define UNLOCK_MUTEX_AND_BAIL_OUT(__mutex, __label) \ { VOID(pthread_mutex_unlock(&__mutex)); goto __label; } -enum evex_table_field -{ - EVEX_FIELD_DB = 0, - EVEX_FIELD_NAME, - EVEX_FIELD_BODY, - EVEX_FIELD_DEFINER, - EVEX_FIELD_EXECUTE_AT, - EVEX_FIELD_INTERVAL_EXPR, - EVEX_FIELD_TRANSIENT_INTERVAL, - EVEX_FIELD_CREATED, - EVEX_FIELD_MODIFIED, - EVEX_FIELD_LAST_EXECUTED, - EVEX_FIELD_STARTS, - EVEX_FIELD_ENDS, - EVEX_FIELD_STATUS, - EVEX_FIELD_ON_COMPLETION, - EVEX_FIELD_COMMENT, - EVEX_FIELD_COUNT /* a cool trick to count the number of fields :) */ -} ; - #define EVEX_DB_FIELD_LEN 64 #define EVEX_NAME_FIELD_LEN 64 #define EVEX_MAX_INTERVAL_VALUE 2147483647L @@ -53,11 +33,10 @@ my_time_compare(TIME *a, TIME *b); int evex_db_find_event_aux(THD *thd, const LEX_STRING dbname, - const LEX_STRING rname, TABLE *table); + const LEX_STRING rname, + const LEX_STRING definer, + TABLE *table); -int -evex_open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table); - int event_timed_compare_q(void *vptr, byte* a, byte *b); diff --git a/sql/event_timed.cc b/sql/event_timed.cc index 4d3dea42e34..deab6e84c4f 100644 --- a/sql/event_timed.cc +++ b/sql/event_timed.cc @@ -413,6 +413,16 @@ event_timed::init_definer(THD *thd) definer_host.str= strdup_root(thd->mem_root, thd->security_ctx->priv_host); definer_host.length= strlen(thd->security_ctx->priv_host); + + definer.length= definer_user.length + definer_host.length + 1; + definer.str= alloc_root(thd->mem_root, definer.length + 1); + + memcpy(definer.str, definer_user.str, definer_user.length); + definer.str[definer_user.length]= '@'; + + memcpy(definer.str + definer_user.length + 1, definer_host.str, + definer_host.length); + definer.str[definer.length]= '\0'; DBUG_RETURN(0); } @@ -486,7 +496,6 @@ event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table) et->definer_host.str= strmake_root(mem_root, ptr + 1, len);//1: because of @ et->definer_host.length= len; - res1= table->field[EVEX_FIELD_STARTS]-> get_date(&et->starts, TIME_NO_ZERO_DATE); @@ -542,8 +551,7 @@ event_timed::load_from_row(MEM_ROOT *mem_root, TABLE *table) goto error; DBUG_PRINT("load_from_row", ("Event [%s] is [%s]", et->name.str, ptr)); - et->status= (ptr[0]=='E'? MYSQL_EVENT_ENABLED: - MYSQL_EVENT_DISABLED); + et->status= (ptr[0]=='E'? MYSQL_EVENT_ENABLED:MYSQL_EVENT_DISABLED); // ToDo : Andrey . Find a way not to allocate ptr on event_mem_root if ((ptr= get_field(mem_root, @@ -681,7 +689,8 @@ event_timed::compute_next_execution_time() } time((time_t *)&now); my_tz_UTC->gmt_sec_to_TIME(&time_now, now); -/* + +#ifdef ANDREY_0 sql_print_information("[%s.%s]", dbname.str, name.str); sql_print_information("time_now : [%d-%d-%d %d:%d:%d ]", time_now.year, time_now.month, time_now.day, @@ -696,7 +705,8 @@ event_timed::compute_next_execution_time() last_executed.month, last_executed.day, last_executed.hour, last_executed.minute, last_executed.second); -*/ +#endif + //if time_now is after ends don't execute anymore if (ends.year && (tmp= my_time_compare(&ends, &time_now)) == -1) { @@ -871,7 +881,7 @@ event_timed::drop(THD *thd) if (evex_open_event_table(thd, TL_WRITE, &table)) DBUG_RETURN(-1); - if (evex_db_find_event_aux(thd, dbname, name, table)) + if (evex_db_find_event_aux(thd, dbname, name, definer, table)) DBUG_RETURN(-2); if ((ret= table->file->ha_delete_row(table->record[0]))) @@ -907,11 +917,12 @@ event_timed::update_fields(THD *thd) } - if ((ret= evex_db_find_event_aux(thd, dbname, name, table))) + if ((ret= evex_db_find_event_aux(thd, dbname, name, definer, table))) goto done; store_record(table,record[1]); - table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; // Don't update create on row update. + // Don't update create on row update. + table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; if (last_executed_changed) { diff --git a/sql/mysqld.cc b/sql/mysqld.cc index 50617521e72..f5b93e6a5e5 100644 --- a/sql/mysqld.cc +++ b/sql/mysqld.cc @@ -6718,6 +6718,7 @@ SHOW_VAR status_vars[]= { {"Com_show_engine_logs", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_ENGINE_LOGS]), SHOW_LONG_STATUS}, {"Com_show_engine_mutex", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_ENGINE_MUTEX]), SHOW_LONG_STATUS}, {"Com_show_engine_status", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_ENGINE_STATUS]), SHOW_LONG_STATUS}, + {"Com_show_events", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_EVENTS]), SHOW_LONG_STATUS}, {"Com_show_errors", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_ERRORS]), SHOW_LONG_STATUS}, {"Com_show_fields", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_FIELDS]), SHOW_LONG_STATUS}, {"Com_show_grants", (char*) offsetof(STATUS_VAR, com_stat[(uint) SQLCOM_SHOW_GRANTS]), SHOW_LONG_STATUS}, diff --git a/sql/sql_lex.h b/sql/sql_lex.h index 67dc903b04b..07a42f7af2c 100644 --- a/sql/sql_lex.h +++ b/sql/sql_lex.h @@ -101,7 +101,7 @@ enum enum_sql_command { SQLCOM_SHOW_AUTHORS, SQLCOM_BINLOG_BASE64_EVENT, SQLCOM_SHOW_PLUGINS, SQLCOM_CREATE_EVENT, SQLCOM_ALTER_EVENT, SQLCOM_DROP_EVENT, - SQLCOM_SHOW_CREATE_EVENT, + SQLCOM_SHOW_CREATE_EVENT, SQLCOM_SHOW_EVENTS, /* This should be the last !!! */ diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index 98ed9353f80..ed7e7dfb684 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -2161,6 +2161,7 @@ int prepare_schema_table(THD *thd, LEX *lex, Table_ident *table_ident, case SCH_TABLES: case SCH_VIEWS: case SCH_TRIGGERS: + case SCH_EVENTS: #ifdef DONT_ALLOW_SHOW_COMMANDS my_message(ER_NOT_ALLOWED_COMMAND, ER(ER_NOT_ALLOWED_COMMAND), MYF(0)); /* purecov: inspected */ @@ -2449,11 +2450,15 @@ mysql_execute_command(THD *thd) if (all_tables) { if (lex->orig_sql_command != SQLCOM_SHOW_STATUS_PROC && - lex->orig_sql_command != SQLCOM_SHOW_STATUS_FUNC) + lex->orig_sql_command != SQLCOM_SHOW_STATUS_FUNC && + lex->orig_sql_command != SQLCOM_SHOW_EVENTS) res= check_table_access(thd, lex->exchange ? SELECT_ACL | FILE_ACL : SELECT_ACL, all_tables, 0); + else if (lex->orig_sql_command == SQLCOM_SHOW_EVENTS) + res= check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0, + is_schema_db(thd->lex->select_lex.db)); } else res= check_access(thd, diff --git a/sql/sql_show.cc b/sql/sql_show.cc index 672f7fe8abe..58f94887ef6 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -25,6 +25,7 @@ #include "sp_head.h" #include "sql_trigger.h" #include "authors.h" +#include "event.h" #include <my_dir.h> #ifdef WITH_PARTITION_STORAGE_ENGINE @@ -1901,6 +1902,7 @@ void get_index_field_values(LEX *lex, INDEX_FIELD_VALUES *index_field_values) case SQLCOM_SHOW_TABLES: case SQLCOM_SHOW_TABLE_STATUS: case SQLCOM_SHOW_TRIGGERS: + case SQLCOM_SHOW_EVENTS: index_field_values->db_value= lex->select_lex.db; index_field_values->table_value= wild; break; @@ -3770,6 +3772,269 @@ static int get_schema_partitions_record(THD *thd, struct st_table_list *tables, } +static LEX_STRING interval_type_to_name[] = { + {(char *) STRING_WITH_LEN("INTERVAL_YEAR")}, + {(char *) STRING_WITH_LEN("INTERVAL_QUARTER")}, + {(char *) STRING_WITH_LEN("INTERVAL_MONTH")}, + {(char *) STRING_WITH_LEN("INTERVAL_DAY")}, + {(char *) STRING_WITH_LEN("INTERVAL_HOUR")}, + {(char *) STRING_WITH_LEN("INTERVAL_MINUTE")}, + {(char *) STRING_WITH_LEN("INTERVAL_WEEK")}, + {(char *) STRING_WITH_LEN("INTERVAL_SECOND")}, + {(char *) STRING_WITH_LEN("INTERVAL_MICROSECOND ")}, + {(char *) STRING_WITH_LEN("INTERVAL_YEAR_MONTH")}, + {(char *) STRING_WITH_LEN("INTERVAL_DAY_HOUR")}, + {(char *) STRING_WITH_LEN("INTERVAL_DAY_MINUTE")}, + {(char *) STRING_WITH_LEN("INTERVAL_DAY_SECOND")}, + {(char *) STRING_WITH_LEN("INTERVAL_HOUR_MINUTE")}, + {(char *) STRING_WITH_LEN("INTERVAL_HOUR_SECOND")}, + {(char *) STRING_WITH_LEN("INTERVAL_MINUTE_SECOND")}, + {(char *) STRING_WITH_LEN("INTERVAL_DAY_MICROSECOND")}, + {(char *) STRING_WITH_LEN("INTERVAL_HOUR_MICROSECOND")}, + {(char *) STRING_WITH_LEN("INTERVAL_MINUTE_MICROSECOND")}, + {(char *) STRING_WITH_LEN("INTERVAL_SECOND_MICROSECOND")} +}; + + +static interval_type get_real_interval_type(interval_type i_type) +{ + switch (i_type) { + case INTERVAL_YEAR: + return INTERVAL_YEAR; + + case INTERVAL_QUARTER: + case INTERVAL_YEAR_MONTH: + case INTERVAL_MONTH: + return INTERVAL_MONTH; + + case INTERVAL_WEEK: + case INTERVAL_DAY: + return INTERVAL_DAY; + + case INTERVAL_DAY_HOUR: + case INTERVAL_HOUR: + return INTERVAL_HOUR; + + case INTERVAL_DAY_MINUTE: + case INTERVAL_HOUR_MINUTE: + case INTERVAL_MINUTE: + return INTERVAL_MINUTE; + + case INTERVAL_DAY_SECOND: + case INTERVAL_HOUR_SECOND: + case INTERVAL_MINUTE_SECOND: + case INTERVAL_SECOND: + return INTERVAL_SECOND; + + case INTERVAL_DAY_MICROSECOND: + case INTERVAL_HOUR_MICROSECOND: + case INTERVAL_MINUTE_MICROSECOND: + case INTERVAL_SECOND_MICROSECOND: + case INTERVAL_MICROSECOND: + return INTERVAL_MICROSECOND; + } + DBUG_ASSERT(0); + return INTERVAL_SECOND; +} + + +static int +fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) +{ + const char *wild= thd->lex->wild ? thd->lex->wild->ptr() : NullS; + CHARSET_INFO *scs= system_charset_info; + TIME time; + event_timed et; + DBUG_ENTER("fill_events_copy_to_schema_tab"); + + restore_record(sch_table, s->default_values); + + if (et.load_from_row(thd->mem_root, event_table)) + { + my_error(ER_EVENT_CANNOT_LOAD_FROM_TABLE, MYF(0)); + DBUG_RETURN(1); + } + + if (!(!wild || !wild[0] || !wild_compare(et.name.str, wild, 0))) + DBUG_RETURN(0); + + //->field[0] is EVENT_CATALOG and is by default NULL + + sch_table->field[1]->store(et.dbname.str, et.dbname.length, scs); + sch_table->field[2]->store(et.name.str, et.name.length, scs); + sch_table->field[3]->store(et.definer.str, et.definer.length, scs); + sch_table->field[4]->store(et.body.str, et.body.length, scs); + + // [9] is SQL_MODE and is NULL for now, will be fixed later + sch_table->field[9]->set_null(); + if (et.expression) + { + //type + sch_table->field[5]->store(STRING_WITH_LEN("RECURRING"), scs); + //execute_at + sch_table->field[6]->set_null(); + //interval_value + sch_table->field[7]->set_notnull(); + sch_table->field[7]->store((longlong) et.expression); + //interval_type + LEX_STRING *ival=&interval_type_to_name[get_real_interval_type(et.interval)]; + sch_table->field[8]->set_notnull(); + sch_table->field[8]->store(ival->str, ival->length, scs); + //starts & ends + sch_table->field[10]->set_notnull(); + sch_table->field[10]->store_time(&et.starts, MYSQL_TIMESTAMP_DATETIME); + sch_table->field[11]->set_notnull(); + sch_table->field[11]->store_time(&et.ends, MYSQL_TIMESTAMP_DATETIME); + } + else + { + //type + sch_table->field[5]->store(STRING_WITH_LEN("ONE TIME"), scs); + //execute_at + sch_table->field[6]->set_notnull(); + sch_table->field[6]->store_time(&et.execute_at, MYSQL_TIMESTAMP_DATETIME); + //interval + sch_table->field[7]->set_null(); + //interval_type + sch_table->field[8]->set_null(); + //starts & ends + sch_table->field[10]->set_null(); + sch_table->field[11]->set_null(); + } + + //status + if (et.status == MYSQL_EVENT_ENABLED) + sch_table->field[12]->store(STRING_WITH_LEN("ENABLED"), scs); + else + sch_table->field[12]->store(STRING_WITH_LEN("DISABLED"), scs); + + //on_completion + if (et.on_completion == MYSQL_EVENT_ON_COMPLETION_DROP) + sch_table->field[13]->store(STRING_WITH_LEN("NOT PRESERVE"), scs); + else + sch_table->field[13]->store(STRING_WITH_LEN("PRESERVE"), scs); + + int not_used=0; + number_to_datetime(et.created, &time, 0, ¬_used); + DBUG_ASSERT(not_used==0); + sch_table->field[14]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); + + number_to_datetime(et.modified, &time, 0, ¬_used); + DBUG_ASSERT(not_used==0); + sch_table->field[15]->store_time(&time, MYSQL_TIMESTAMP_DATETIME); + + if (et.last_executed.year) + sch_table->field[16]->store_time(&et.last_executed,MYSQL_TIMESTAMP_DATETIME); + else + sch_table->field[16]->set_null(); + + sch_table->field[17]->store(et.comment.str, et.comment.length, scs); + + if (schema_table_store_record(thd, sch_table)) + DBUG_RETURN(1); + + DBUG_RETURN(0); +} + + +int fill_schema_events(THD *thd, TABLE_LIST *tables, COND *cond) +{ + TABLE *table= tables->table; + CHARSET_INFO *scs= system_charset_info; + TABLE *event_table= NULL; + Open_tables_state backup; + int ret=0; + bool verbose= false; + char definer[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; + bool use_prefix_scanning= true; + uint key_len= 0; + byte *key_buf= NULL; + LINT_INIT(key_buf); + + DBUG_ENTER("fill_schema_events"); + + strxmov(definer, thd->security_ctx->priv_user,"@",thd->security_ctx->priv_host, + NullS); + + DBUG_PRINT("info",("db=%s current_user=%s", thd->lex->select_lex.db, definer)); + + thd->reset_n_backup_open_tables_state(&backup); + + if ((ret= evex_open_event_table(thd, TL_READ, &event_table))) + { + sql_print_error("Table mysql.event is damaged."); + ret= 1; + goto err; + } + + event_table->file->ha_index_init(0, 1); + + /* + see others' events only if you have PROCESS_ACL !! + thd->lex->verbose is set either if SHOW FULL EVENTS or + in case of SELECT FROM I_S.EVENTS + */ + verbose= (thd->lex->verbose + && (thd->security_ctx->master_access & PROCESS_ACL)); + + if (verbose && thd->security_ctx->user) + { + ret= event_table->file->index_first(event_table->record[0]); + use_prefix_scanning= false; + } + else + { + event_table->field[EVEX_FIELD_DEFINER]->store(definer, strlen(definer), scs); + key_len= event_table->key_info->key_part[0].store_length; + + if (thd->lex->select_lex.db) + { + event_table->field[EVEX_FIELD_DB]-> + store(thd->lex->select_lex.db, strlen(thd->lex->select_lex.db), scs); + key_len+= event_table->key_info->key_part[1].store_length; + } + if (!(key_buf= alloc_root(thd->mem_root, key_len))) + { + ret= 1; + goto err; + } + + key_copy(key_buf, event_table->record[0], event_table->key_info, key_len); + ret= event_table->file->index_read(event_table->record[0], key_buf, key_len, + HA_READ_PREFIX); + } + + if (ret) + { + ret= (ret == HA_ERR_END_OF_FILE || ret == HA_ERR_KEY_NOT_FOUND) ? 0 : 1; + goto err; + } + + while (!ret) + { + if ((ret= fill_events_copy_to_schema_table(thd, table, event_table))) + goto err; + + if (use_prefix_scanning) + ret= event_table->file-> + index_next_same(event_table->record[0], key_buf, key_len); + else + ret= event_table->file->index_next(event_table->record[0]); + } + // ret is guaranteed to be != 0 + ret= (ret != HA_ERR_END_OF_FILE); +err: + if (event_table) + { + event_table->file->ha_index_end(); + close_thread_tables(thd); + } + + thd->restore_backup_open_tables_state(&backup); + DBUG_RETURN(ret); +} + + int fill_open_tables(THD *thd, TABLE_LIST *tables, COND *cond) { DBUG_ENTER("fill_open_tables"); @@ -4390,6 +4655,31 @@ ST_FIELD_INFO engines_fields_info[]= }; +ST_FIELD_INFO events_fields_info[]= +{ + {"EVENT_CATALOG", NAME_LEN, MYSQL_TYPE_STRING, 0, 1, 0}, + {"EVENT_SCHEMA", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Db"}, + {"EVENT_NAME", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, "Name"}, + {"DEFINER", 77, MYSQL_TYPE_STRING, 0, 0, "Definer"}, + {"EVENT_BODY", 65535, MYSQL_TYPE_STRING, 0, 0, 0}, + {"EVENT_TYPE", 9, MYSQL_TYPE_STRING, 0, 0, "Type"}, + {"EXECUTE_AT", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Execute at"}, + {"INTERVAL_VALUE", 11, MYSQL_TYPE_LONG, 0, 1, "Interval value"}, + {"INTERVAL_FIELD", 18, MYSQL_TYPE_STRING, 0, 1, "Interval field"}, + {"SQL_MODE", 65535, MYSQL_TYPE_STRING, 0, 1, 0}, + {"STARTS", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Starts"}, + {"ENDS", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, "Ends"}, + {"STATUS", 8, MYSQL_TYPE_STRING, 0, 0, "Status"}, + {"ON_COMPLETION", 12, MYSQL_TYPE_STRING, 0, 0, 0}, + {"CREATED", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, 0}, + {"LAST_ALTERED", 0, MYSQL_TYPE_TIMESTAMP, 0, 0, 0}, + {"LAST_EXECUTED", 0, MYSQL_TYPE_TIMESTAMP, 0, 1, 0}, + {"EVENT_COMMENT", NAME_LEN, MYSQL_TYPE_STRING, 0, 0, 0}, + {0, 0, MYSQL_TYPE_STRING, 0, 0, 0} +}; + + + ST_FIELD_INFO coll_charset_app_fields_info[]= { {"COLLATION_NAME", 64, MYSQL_TYPE_STRING, 0, 0, 0}, @@ -4655,6 +4945,8 @@ ST_SCHEMA_TABLE schema_tables[]= fill_schema_column_privileges, 0, 0, -1, -1, 0}, {"ENGINES", engines_fields_info, create_schema_table, fill_schema_engines, make_old_format, 0, -1, -1, 0}, + {"EVENTS", events_fields_info, create_schema_table, + fill_schema_events, make_old_format, 0, -1, -1, 0}, {"KEY_COLUMN_USAGE", key_column_usage_fields_info, create_schema_table, get_all_tables, 0, get_schema_key_column_usage_record, 4, 5, 0}, {"OPEN_TABLES", open_tables_fields_info, create_schema_table, diff --git a/sql/sql_yacc.yy b/sql/sql_yacc.yy index c5f4b81fa72..a86eccb493f 100644 --- a/sql/sql_yacc.yy +++ b/sql/sql_yacc.yy @@ -1355,8 +1355,11 @@ create: $<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES; YYTHD->client_capabilities &= (~CLIENT_MULTI_QUERIES); - if (!lex->et_compile_phase) + if (!lex->et_compile_phase) + { lex->et->init_name(YYTHD, $4); + lex->et->init_definer(YYTHD); + } } ON SCHEDULE_SYM ev_schedule_time opt_ev_on_completion @@ -1599,7 +1602,6 @@ ev_sql_stmt: if (!lex->et_compile_phase) { lex->et->init_body(YYTHD); - lex->et->init_definer(YYTHD); } } ; @@ -4816,8 +4818,13 @@ alter: if (!(et= new event_timed()))// implicitly calls event_timed::init() YYABORT; lex->et = et; - et->init_name(YYTHD, $3); + if (!lex->et_compile_phase) + { + et->init_definer(YYTHD); + 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 @@ -4825,7 +4832,6 @@ alter: */ $<ulong_num>$= YYTHD->client_capabilities & CLIENT_MULTI_QUERIES; YYTHD->client_capabilities &= ~CLIENT_MULTI_QUERIES; - } ev_alter_on_schedule_completion opt_ev_rename_to @@ -7664,7 +7670,6 @@ drop: if (lex->et) { - // ToDo Andrey : Change the error message /* Recursive events are not possible because recursive SPs are not also possible. lex->sp_head is not stacked. @@ -7675,8 +7680,13 @@ drop: if (!(lex->et= new event_timed())) YYABORT; - lex->et->init_name(YYTHD, $4); + if (!lex->et_compile_phase) + { + lex->et->init_name(YYTHD, $4); + lex->et->init_definer(YYTHD); + } + lex->sql_command = SQLCOM_DROP_EVENT; lex->drop_if_exists= $3; } @@ -8068,6 +8078,15 @@ show_param: if (prepare_schema_table(YYTHD, lex, 0, SCH_TRIGGERS)) YYABORT; } + | opt_full EVENTS_SYM opt_db wild_and_where + { + LEX *lex= Lex; + lex->sql_command= SQLCOM_SELECT; + lex->orig_sql_command= SQLCOM_SHOW_EVENTS; + lex->select_lex.db= $3; + if (prepare_schema_table(YYTHD, lex, 0, SCH_EVENTS)) + YYABORT; + } | TABLE_SYM STATUS_SYM opt_db wild_and_where { LEX *lex= Lex; diff --git a/sql/table.h b/sql/table.h index eb0c0cf98d3..213310a51dc 100644 --- a/sql/table.h +++ b/sql/table.h @@ -338,6 +338,7 @@ enum enum_schema_tables SCH_COLUMNS, SCH_COLUMN_PRIVILEGES, SCH_ENGINES, + SCH_EVENTS, SCH_KEY_COLUMN_USAGE, SCH_OPEN_TABLES, SCH_PARTITIONS, |