diff options
author | unknown <andrey@lmy004.> | 2006-05-29 10:39:45 +0200 |
---|---|---|
committer | unknown <andrey@lmy004.> | 2006-05-29 10:39:45 +0200 |
commit | bdda01167579c5b846524d595b35027522d0f1ff (patch) | |
tree | b5f8f9d86c6ec5a1912796534ba3ae361f6f2d8b | |
parent | c4c26017c95ad50024c249168a803f6b6940e23b (diff) | |
download | mariadb-git-bdda01167579c5b846524d595b35027522d0f1ff.tar.gz |
Fix for bug #17394 - Events namespace is wrong
mysql-test/lib/init_db.sql:
remove definer from PK
mysql-test/r/events.result:
update results
mysql-test/r/system_mysql_db.result:
update results
mysql-test/t/events.test:
remove I_S.EVENTS test and move it to events_grant.test
scripts/mysql_fix_privilege_tables.sql:
change table definition
sql/event.cc:
make events non-user specific (namespace change)
sql/event.h:
make events non-user specific (namespace change)
sql/event_priv.h:
make events non-user specific (namespace change)
sql/event_scheduler.cc:
make events non-user specific (namespace change)
sql/event_timed.cc:
make events non-user specific (namespace change)
sql/sql_parse.cc:
make events non-user specific (namespace change)
sql/sql_show.cc:
SHOW EVENTS is available to everyone who has EVENT on specific schema.
No additional privileges are needed to see others' events.
- user A has events in db1 and db2
- user B has events in db1 and db3
A will see all his events from db1 and db2 as well as B's events
from db1 but not from db3.
B will see her events from db1 and db3. In addition B will see
only A's events from db1 but not db2.
-rw-r--r-- | mysql-test/lib/init_db.sql | 2 | ||||
-rw-r--r-- | mysql-test/r/events.result | 83 | ||||
-rw-r--r-- | mysql-test/r/system_mysql_db.result | 2 | ||||
-rw-r--r-- | mysql-test/t/events.test | 83 | ||||
-rw-r--r-- | scripts/mysql_fix_privilege_tables.sql | 4 | ||||
-rw-r--r-- | sql/event.cc | 87 | ||||
-rw-r--r-- | sql/event.h | 2 | ||||
-rw-r--r-- | sql/event_priv.h | 5 | ||||
-rw-r--r-- | sql/event_scheduler.cc | 18 | ||||
-rw-r--r-- | sql/event_timed.cc | 9 | ||||
-rw-r--r-- | sql/sql_parse.cc | 10 | ||||
-rw-r--r-- | sql/sql_show.cc | 262 |
12 files changed, 257 insertions, 310 deletions
diff --git a/mysql-test/lib/init_db.sql b/mysql-test/lib/init_db.sql index a7079b0ac33..a5736ed4b9b 100644 --- a/mysql-test/lib/init_db.sql +++ b/mysql-test/lib/init_db.sql @@ -631,7 +631,7 @@ CREATE TABLE event ( 'HIGH_NOT_PRECEDENCE' ) DEFAULT '' NOT NULL, comment char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', - PRIMARY KEY (definer, db, name) + PRIMARY KEY (db, name) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT 'Events'; CREATE DATABASE IF NOT EXISTS cluster; diff --git a/mysql-test/r/events.result b/mysql-test/r/events.result index d02a2af3c9f..77280f99b7c 100644 --- a/mysql-test/r/events.result +++ b/mysql-test/r/events.result @@ -254,7 +254,7 @@ event CREATE TABLE `event` ( `on_completion` enum('DROP','PRESERVE') NOT NULL DEFAULT 'DROP', `sql_mode` set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER','HIGH_NOT_PRECEDENCE') NOT NULL DEFAULT '', `comment` char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', - PRIMARY KEY (`definer`,`db`,`name`) + PRIMARY KEY (`db`,`name`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Events' SELECT event_name FROM INFORMATION_SCHEMA.EVENTS; ERROR HY000: Cannot load from mysql.event. Table probably corrupted. See error log. @@ -280,84 +280,6 @@ SHOW EVENTS; Db Name Definer Type Execute at Interval value Interval field Starts Ends Status events_test intact_check root@localhost RECURRING NULL 10 HOUR # # ENABLED DROP EVENT intact_check; -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 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 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, TRIGGER ON `events_test2`.* TO 'ev_test'@'localhost' -"Here comes an error:"; -SHOW EVENTS; -ERROR 42000: Access denied for user 'ev_test'@'localhost' to database 'events_test2' -USE events_test; -"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; -"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 SECOND # # ENABLED -events_test three_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED -events_test two_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED -"This should show us only 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 SECOND # # ENABLED -events_test three_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED -events_test two_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED -"This should show us only 2 events:"; -SHOW 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 SECOND # # ENABLED -events_test two_event ev_test@localhost RECURRING NULL 20 SECOND # # ENABLED -"This should show us no events:"; -SHOW EVENTS FROM test LIKE '%'; -Db Name Definer Type Execute at Interval value Interval field Starts Ends Status -DROP DATABASE events_test2; -"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 SECOND # # ENABLED -"we should see 4 events now:"; -SHOW EVENTS; -Db Name Definer Type Execute at Interval value Interval field Starts Ends Status -events_test one_event root@localhost RECURRING NULL 10 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 SECOND ENABLED NOT PRESERVE -NULL events_test three_event ev_test@localhost select 123 RECURRING NULL 20 SECOND ENABLED PRESERVE three event -NULL events_test two_event ev_test@localhost select 123 RECURRING NULL 20 SECOND ENABLED NOT PRESERVE two event -NULL events_test one_event root@localhost select 123 RECURRING NULL 10 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; -"Sleep a bit so the server closes the second connection" 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; db name body definer convert_tz(execute_at, 'UTC', 'SYSTEM') on_completion @@ -452,9 +374,6 @@ select 2; select event_schema, event_name, definer, event_body from information_schema.events where event_name='white_space'; event_schema event_name definer event_body events_test white_space root@localhost select 2 -select event_schema, event_name, definer, event_body from information_schema.events where event_name='white_space'; -event_schema event_name definer event_body -events_test white_space root@localhost select 2 drop event white_space; create event white_space on schedule every 10 hour disable do select 3; select event_schema, event_name, definer, event_body from information_schema.events where event_name='white_space'; diff --git a/mysql-test/r/system_mysql_db.result b/mysql-test/r/system_mysql_db.result index 30cde39531d..b9d3504993c 100644 --- a/mysql-test/r/system_mysql_db.result +++ b/mysql-test/r/system_mysql_db.result @@ -208,7 +208,7 @@ event CREATE TABLE `event` ( `on_completion` enum('DROP','PRESERVE') NOT NULL DEFAULT 'DROP', `sql_mode` set('REAL_AS_FLOAT','PIPES_AS_CONCAT','ANSI_QUOTES','IGNORE_SPACE','NOT_USED','ONLY_FULL_GROUP_BY','NO_UNSIGNED_SUBTRACTION','NO_DIR_IN_CREATE','POSTGRESQL','ORACLE','MSSQL','DB2','MAXDB','NO_KEY_OPTIONS','NO_TABLE_OPTIONS','NO_FIELD_OPTIONS','MYSQL323','MYSQL40','ANSI','NO_AUTO_VALUE_ON_ZERO','NO_BACKSLASH_ESCAPES','STRICT_TRANS_TABLES','STRICT_ALL_TABLES','NO_ZERO_IN_DATE','NO_ZERO_DATE','INVALID_DATES','ERROR_FOR_DIVISION_BY_ZERO','TRADITIONAL','NO_AUTO_CREATE_USER','HIGH_NOT_PRECEDENCE') NOT NULL DEFAULT '', `comment` char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL DEFAULT '', - PRIMARY KEY (`definer`,`db`,`name`) + PRIMARY KEY (`db`,`name`) ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COMMENT='Events' show create table general_log; Table Create Table diff --git a/mysql-test/t/events.test b/mysql-test/t/events.test index 819d64ccf14..a3e2bbc0998 100644 --- a/mysql-test/t/events.test +++ b/mysql-test/t/events.test @@ -148,9 +148,9 @@ set names cp1251; create event ðóóò21 on schedule every '50:23:59:95' day_second COMMENT 'òîâà å 1251 êîìåíòàð' do select 1; SHOW CREATE EVENT ðóóò21; insert into mysql.event (db, name, body, definer, interval_value, interval_field) values (database(), "root22", "select 1", user(), 100, "SECOND_MICROSECOND"); ---error 1235 +--error ER_NOT_SUPPORTED_YET show create event root22; ---error 1235 +--error ER_NOT_SUPPORTED_YET SHOW EVENTS; drop event root22; drop event root6; @@ -239,82 +239,6 @@ DROP EVENT intact_check; # mysql.event intact checking end # -# -#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; - ---echo "Here comes an error:"; -#NO EVENT_ACL on events_test2 ---error 1044 -SHOW EVENTS; -USE events_test; - ---echo "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; - ---echo "Now we should see 3 events:"; ---replace_column 8 # 9 # -SHOW EVENTS; - ---echo "This should show us only 3 events:"; ---replace_column 8 # 9 # -SHOW EVENTS; - ---echo "This should show us only 2 events:"; ---replace_column 8 # 9 # -SHOW EVENTS LIKE 't%event'; - ---echo "This should show us no events:"; ---replace_column 8 # 9 # -SHOW EVENTS FROM test LIKE '%'; -#ok, we are back -connection default; -DROP DATABASE events_test2; - ---echo "should see 1 event:"; ---replace_column 8 # 9 # -SHOW EVENTS; - ---echo "we should see 4 events now:"; ---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; - -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 -# - ---echo "Sleep a bit so the server closes the second connection" ---sleep 2 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; drop event e_26; @@ -358,7 +282,7 @@ select get_lock("test_lock2", 20); --echo "Create an event which tries to acquire a mutex. The event locks on the mutex" create event закачка on schedule every 10 hour do select get_lock("test_lock2", 20); --echo "Let some time pass to the event starts" ---sleep 2 +--sleep 1 --echo "Should have only 2 processes: the scheduler and the locked event" select /*2*/ user, host, db, command, state, info from information_schema.processlist where info is null or info not like '%processlist%' order by info;--echo "Release the mutex, the event worker should finish." --echo "Release the mutex, the event worker should finish." @@ -409,7 +333,6 @@ create event white_space on schedule every 10 hour disable do select 2; select event_schema, event_name, definer, event_body from information_schema.events where event_name='white_space'; -select event_schema, event_name, definer, event_body from information_schema.events where event_name='white_space'; drop event white_space; create event white_space on schedule every 10 hour disable do select 3; select event_schema, event_name, definer, event_body from information_schema.events where event_name='white_space'; diff --git a/scripts/mysql_fix_privilege_tables.sql b/scripts/mysql_fix_privilege_tables.sql index 5b3cab16db2..f3c0c7f13be 100644 --- a/scripts/mysql_fix_privilege_tables.sql +++ b/scripts/mysql_fix_privilege_tables.sql @@ -570,7 +570,7 @@ DROP PROCEDURE create_log_tables; CREATE TABLE event ( db char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', - name char(64) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', + name char(64) CHARACTER SET utf8 NOT NULL default '', body longblob NOT NULL, definer char(77) CHARACTER SET utf8 COLLATE utf8_bin NOT NULL default '', execute_at DATETIME default NULL, @@ -636,7 +636,7 @@ SELECT @hadEventPriv :=1 FROM user WHERE Event_priv LIKE '%'; 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); +ALTER TABLE event ADD PRIMARY KEY(db, name); ALTER TABLE event ADD sql_mode set('REAL_AS_FLOAT', 'PIPES_AS_CONCAT', diff --git a/sql/event.cc b/sql/event.cc index 7c3f17304aa..5273394640c 100644 --- a/sql/event.cc +++ b/sql/event.cc @@ -456,7 +456,7 @@ Events::open_event_table(THD *thd, enum thr_lock_type lock_type, SYNOPSIS evex_db_find_event_aux() thd Thread context - et evet_timed object containing dbname, name & definer + et event_timed object containing dbname & name table TABLE object for open mysql.event table. RETURN VALUE @@ -467,8 +467,7 @@ Events::open_event_table(THD *thd, enum thr_lock_type lock_type, inline int evex_db_find_event_aux(THD *thd, Event_timed *et, TABLE *table) { - return evex_db_find_event_by_name(thd, et->dbname, et->name, - et->definer, table); + return evex_db_find_event_by_name(thd, et->dbname, et->name, table); } @@ -490,7 +489,6 @@ evex_db_find_event_aux(THD *thd, Event_timed *et, TABLE *table) int evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname, const LEX_STRING ev_name, - const LEX_STRING user_name, TABLE *table) { byte key[MAX_KEY_LENGTH]; @@ -505,18 +503,14 @@ evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname, same fields. */ if (dbname.length > table->field[Events::FIELD_DB]->field_length || - ev_name.length > table->field[Events::FIELD_NAME]->field_length || - user_name.length > table->field[Events::FIELD_DEFINER]->field_length) + ev_name.length > table->field[Events::FIELD_NAME]->field_length) DBUG_RETURN(EVEX_KEY_NOT_FOUND); table->field[Events::FIELD_DB]->store(dbname.str, dbname.length, - &my_charset_bin); + &my_charset_bin); table->field[Events::FIELD_NAME]->store(ev_name.str, ev_name.length, - &my_charset_bin); - table->field[Events::FIELD_DEFINER]->store(user_name.str, - user_name.length, - &my_charset_bin); + &my_charset_bin); key_copy(key, table->record[0], table->key_info, table->key_info->key_length); @@ -553,6 +547,7 @@ evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname, static int evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update) { + CHARSET_INFO *scs= system_charset_info; enum Events::enum_table_field field_num; DBUG_ENTER("evex_fill_row"); @@ -561,20 +556,23 @@ evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update) DBUG_PRINT("info", ("name =[%s]", et->name.str)); DBUG_PRINT("info", ("body =[%s]", et->body.str)); + if (table->field[field_num= Events::FIELD_DEFINER]-> + store(et->definer.str, et->definer.length, scs)) + goto err_truncate; + if (table->field[field_num= Events::FIELD_DB]-> - store(et->dbname.str, et->dbname.length, system_charset_info)) - goto trunc_err; + store(et->dbname.str, et->dbname.length, scs)) + goto err_truncate; if (table->field[field_num= Events::FIELD_NAME]-> - store(et->name.str, et->name.length, system_charset_info)) - goto trunc_err; + store(et->name.str, et->name.length, scs)) + goto err_truncate; /* both ON_COMPLETION and STATUS are NOT NULL thus not calling set_notnull()*/ table->field[Events::FIELD_ON_COMPLETION]-> store((longlong)et->on_completion, true); - table->field[Events::FIELD_STATUS]-> - store((longlong)et->status, true); + table->field[Events::FIELD_STATUS]->store((longlong)et->status, true); /* Change the SQL_MODE only if body was present in an ALTER EVENT and of course @@ -586,8 +584,8 @@ evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update) store((longlong)thd->variables.sql_mode, true); if (table->field[field_num= Events::FIELD_BODY]-> - store(et->body.str, et->body.length, system_charset_info)) - goto trunc_err; + store(et->body.str, et->body.length, scs)) + goto err_truncate; } if (et->expression) @@ -645,12 +643,12 @@ evex_fill_row(THD *thd, TABLE *table, Event_timed *et, my_bool is_update) if (et->comment.str) { if (table->field[field_num= Events::FIELD_COMMENT]-> - store(et->comment.str, et->comment.length, system_charset_info)) - goto trunc_err; + store(et->comment.str, et->comment.length, scs)) + goto err_truncate; } DBUG_RETURN(0); -trunc_err: +err_truncate: my_error(ER_EVENT_DATA_TOO_LONG, MYF(0), table->field[field_num]->field_name); DBUG_RETURN(EVEX_GENERAL_ERROR); } @@ -746,13 +744,6 @@ db_create_event(THD *thd, Event_timed *et, my_bool create_if_not, goto err; } - if ((ret=table->field[Events::FIELD_DEFINER]-> - store(et->definer.str, et->definer.length, scs))) - { - my_error(ER_EVENT_STORE_FAILED, MYF(0), et->name.str, ret); - goto err; - } - ((Field_timestamp *)table->field[Events::FIELD_CREATED])->set_time(); /* @@ -816,6 +807,7 @@ err: static int db_update_event(THD *thd, Event_timed *et, sp_name *new_name) { + CHARSET_INFO *scs= system_charset_info; TABLE *table; int ret= EVEX_OPEN_TABLE_FAILED; DBUG_ENTER("db_update_event"); @@ -835,22 +827,21 @@ db_update_event(THD *thd, Event_timed *et, sp_name *new_name) /* first look whether we overwrite */ if (new_name) { - if (!sortcmp_lex_string(et->name, new_name->m_name, system_charset_info) && - !sortcmp_lex_string(et->dbname, new_name->m_db, system_charset_info)) + if (!sortcmp_lex_string(et->name, new_name->m_name, scs) && + !sortcmp_lex_string(et->dbname, new_name->m_db, scs)) { my_error(ER_EVENT_SAME_NAME, MYF(0), et->name.str); goto err; } - if (!evex_db_find_event_by_name(thd, new_name->m_db, new_name->m_name, - et->definer, table)) + if (!evex_db_find_event_by_name(thd,new_name->m_db,new_name->m_name,table)) { my_error(ER_EVENT_ALREADY_EXISTS, MYF(0), new_name->m_name.str); goto err; } } /* - ...and then whether there is such an event. don't exchange the blocks + ...and then if there is such an event. Don't exchange the blocks because you will get error 120 from table handler because new_name will overwrite the key and SE will tell us that it cannot find the already found row (copied into record[1] later @@ -866,16 +857,19 @@ db_update_event(THD *thd, Event_timed *et, sp_name *new_name) /* Don't update create on row update. */ table->timestamp_field_type= TIMESTAMP_NO_AUTO_SET; - /* evex_fill_row() calls my_error() in case of error so no need to handle it here */ + /* + evex_fill_row() calls my_error() in case of error so no need to + handle it here + */ if ((ret= evex_fill_row(thd, table, et, true))) goto err; if (new_name) { table->field[Events::FIELD_DB]-> - store(new_name->m_db.str, new_name->m_db.length, system_charset_info); + store(new_name->m_db.str, new_name->m_db.length, scs); table->field[Events::FIELD_NAME]-> - store(new_name->m_name.str, new_name->m_name.length, system_charset_info); + store(new_name->m_name.str, new_name->m_name.length, scs); } if ((ret= table->file->ha_update_row(table->record[1], table->record[0]))) @@ -903,7 +897,6 @@ 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 @@ -917,12 +910,12 @@ err: */ int -db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, Event_timed **ett, - TABLE *tbl, MEM_ROOT *root) +db_find_event(THD *thd, sp_name *name, Event_timed **ett, TABLE *tbl, + MEM_ROOT *root) { TABLE *table; int ret; - Event_timed *et=NULL; + Event_timed *et= NULL; DBUG_ENTER("db_find_event"); DBUG_PRINT("enter", ("name: %*s", name->m_name.length, name->m_name.str)); @@ -938,8 +931,7 @@ db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, Event_timed **ett, goto done; } - if ((ret= evex_db_find_event_by_name(thd, name->m_db, name->m_name, *definer, - table))) + if ((ret= evex_db_find_event_by_name(thd, name->m_db, name->m_name, table))) { my_error(ER_EVENT_DOES_NOT_EXIST, MYF(0), name->m_name.str); goto done; @@ -959,7 +951,7 @@ db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, Event_timed **ett, } done: - if (ret && et) + if (ret) { delete et; et= 0; @@ -994,7 +986,7 @@ done: int Events::create_event(THD *thd, Event_timed *et, uint create_options, - uint *rows_affected) + uint *rows_affected) { int ret; @@ -1166,7 +1158,6 @@ Events::drop_event(THD *thd, Event_timed *et, bool drop_if_exists, Events::show_create_event() thd THD spn the name of the event (db, name) - definer the definer of the event RETURN VALUE 0 OK @@ -1174,7 +1165,7 @@ Events::drop_event(THD *thd, Event_timed *et, bool drop_if_exists, */ int -Events::show_create_event(THD *thd, sp_name *spn, LEX_STRING definer) +Events::show_create_event(THD *thd, sp_name *spn) { int ret; Event_timed *et= NULL; @@ -1184,7 +1175,7 @@ Events::show_create_event(THD *thd, sp_name *spn, LEX_STRING definer) DBUG_PRINT("enter", ("name: %*s", spn->m_name.length, spn->m_name.str)); thd->reset_n_backup_open_tables_state(&backup); - ret= db_find_event(thd, spn, &definer, &et, NULL, thd->mem_root); + ret= db_find_event(thd, spn, &et, NULL, thd->mem_root); thd->restore_backup_open_tables_state(&backup); if (!ret) diff --git a/sql/event.h b/sql/event.h index 40ede7b0c5f..02c5fa78150 100644 --- a/sql/event.h +++ b/sql/event.h @@ -85,7 +85,7 @@ public: open_event_table(THD *thd, enum thr_lock_type lock_type, TABLE **table); static int - show_create_event(THD *thd, sp_name *spn, LEX_STRING definer); + show_create_event(THD *thd, sp_name *spn); static int reconstruct_interval_expression(String *buf, interval_type interval, diff --git a/sql/event_priv.h b/sql/event_priv.h index b0a18377ace..43ef30a659f 100644 --- a/sql/event_priv.h +++ b/sql/event_priv.h @@ -33,7 +33,6 @@ my_time_compare(TIME *a, TIME *b); int evex_db_find_event_by_name(THD *thd, const LEX_STRING dbname, const LEX_STRING ev_name, - const LEX_STRING user_name, TABLE *table); int @@ -43,8 +42,8 @@ int db_drop_event(THD *thd, Event_timed *et, bool drop_if_exists, uint *rows_affected); int -db_find_event(THD *thd, sp_name *name, LEX_STRING *definer, Event_timed **ett, - TABLE *tbl, MEM_ROOT *root); +db_find_event(THD *thd, sp_name *name, Event_timed **ett, TABLE *tbl, + MEM_ROOT *root); int db_create_event(THD *thd, Event_timed *et, my_bool create_if_not, diff --git a/sql/event_scheduler.cc b/sql/event_scheduler.cc index 784c87c0e8e..99c75a5a95d 100644 --- a/sql/event_scheduler.cc +++ b/sql/event_scheduler.cc @@ -1292,11 +1292,17 @@ Event_scheduler::run(THD *thd) /* Skip disabled events */ if (et->status != Event_timed::ENABLED) { - sql_print_error("SCHEDULER: Found a disabled event %*s.%*s in the queue", - et->dbname.length, et->dbname.str, et->name.length, - et->name.str); + /* + It could be a one-timer scheduled for a time, already in the past when the + scheduler was suspended. + */ + sql_print_information("SCHEDULER: Found a disabled event %*s.%*s in the queue", + et->dbname.length, et->dbname.str, et->name.length, + et->name.str); queue_remove(&queue, 0); /* ToDo: check this again */ + if (et->dropped) + et->drop(thd); delete et; UNLOCK_SCHEDULER_DATA(); continue; @@ -1805,7 +1811,10 @@ Event_scheduler::check_n_suspend_if_needed(THD *thd) DBUG_PRINT("info", ("We have to recompute the execution times")); for (i= 0; i < queue.elements; i++) + { ((Event_timed*)queue_element(&queue, i))->compute_next_execution_time(); + ((Event_timed*)queue_element(&queue, i))->update_fields(thd); + } queue_fix(&queue); } /* This will implicitly unlock LOCK_scheduler_data */ @@ -2050,8 +2059,7 @@ Event_scheduler::load_event(THD *thd, Event_timed *etn, Event_timed **etn_new) /* No need to use my_error() here because db_find_event() has done it */ { sp_name spn(etn->dbname, etn->name); - ret= db_find_event(thd, &spn, &etn->definer, &et_loaded, NULL, - &scheduler_root); + ret= db_find_event(thd, &spn, &et_loaded, NULL, &scheduler_root); } thd->restore_backup_open_tables_state(&backup); /* In this case no memory was allocated so we don't need to clean */ diff --git a/sql/event_timed.cc b/sql/event_timed.cc index fd85f5ebecc..9edf51e20cb 100644 --- a/sql/event_timed.cc +++ b/sql/event_timed.cc @@ -961,7 +961,7 @@ Event_timed::compute_next_execution_time() } goto ret; } - current_thd->end_time(); + my_tz_UTC->gmt_sec_to_TIME(&time_now, current_thd->query_start()); DBUG_PRINT("info",("NOW=[%llu]", TIME_to_ulonglong_datetime(&time_now))); @@ -975,6 +975,7 @@ Event_timed::compute_next_execution_time() execute_at_null= TRUE; if (on_completion == Event_timed::ON_COMPLETION_DROP) dropped= true; + DBUG_PRINT("info", ("Dropped=%d", dropped)); status= Event_timed::DISABLED; status_changed= true; @@ -1225,7 +1226,7 @@ Event_timed::update_fields(THD *thd) { TABLE *table; Open_tables_state backup; - int ret= 0; + int ret; DBUG_ENTER("Event_timed::update_time_fields"); @@ -1233,7 +1234,7 @@ Event_timed::update_fields(THD *thd) /* No need to update if nothing has changed */ if (!(status_changed || last_executed_changed)) - goto done; + DBUG_RETURN(0); thd->reset_n_backup_open_tables_state(&backup); @@ -1244,7 +1245,7 @@ Event_timed::update_fields(THD *thd) } - if ((ret= evex_db_find_event_by_name(thd, dbname, name, definer, table))) + if ((ret= evex_db_find_event_by_name(thd, dbname, name, table))) goto done; store_record(table,record[1]); diff --git a/sql/sql_parse.cc b/sql/sql_parse.cc index af6ac7d862a..ccf7500f53d 100644 --- a/sql/sql_parse.cc +++ b/sql/sql_parse.cc @@ -3837,16 +3837,16 @@ end_with_restore_list: switch (lex->sql_command) { case SQLCOM_CREATE_EVENT: res= Events::create_event(thd, lex->et, - (uint) lex->create_info.options, - &rows_affected); + (uint) lex->create_info.options, + &rows_affected); break; case SQLCOM_ALTER_EVENT: res= Events::update_event(thd, lex->et, lex->spname, - &rows_affected); + &rows_affected); break; case SQLCOM_DROP_EVENT: res= Events::drop_event(thd, lex->et, lex->drop_if_exists, - &rows_affected); + &rows_affected); default:; } DBUG_PRINT("info", ("CREATE/ALTER/DROP returned error code=%d af_rows=%d", @@ -3884,7 +3884,7 @@ end_with_restore_list: my_error(ER_TOO_LONG_IDENT, MYF(0), lex->spname->m_name.str); goto error; } - res= Events::show_create_event(thd, lex->spname, lex->et->definer); + res= Events::show_create_event(thd, lex->spname); break; } #ifndef DBUG_OFF diff --git a/sql/sql_show.cc b/sql/sql_show.cc index f94ddc57c80..7776915b23a 100644 --- a/sql/sql_show.cc +++ b/sql/sql_show.cc @@ -4020,8 +4020,24 @@ static interval_type get_real_interval_type(interval_type i_type) extern LEX_STRING interval_type_to_name[]; + +/* + Loads an event from mysql.event and copies it's data to a row of + I_S.EVENTS + + Synopsis + copy_event_to_schema_table() + thd Thread + sch_table The schema table (information_schema.event) + event_table The event table to use for loading (mysql.event). + + Returns + 0 OK + 1 Error +*/ + static int -fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) +copy_event_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; @@ -4039,9 +4055,19 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) if (!(!wild || !wild[0] || !wild_compare(et.name.str, wild, 0))) DBUG_RETURN(0); - + + /* + Skip events in schemas one does not have access to. The check is + optimized. It's guaranteed in case of SHOW EVENTS that the user + has access. + */ + if (thd->lex->orig_sql_command != SQLCOM_SHOW_EVENTS && + check_access(thd, EVENT_ACL, et.dbname.str, 0, 0, 1, + is_schema_db(et.dbname.str))) + 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); @@ -4053,19 +4079,18 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) ulong sql_mode_len=0; sql_mode_str= sys_var_thd_sql_mode::symbolic_mode_representation(thd, et.sql_mode, - &sql_mode_len); + &sql_mode_len); sch_table->field[9]->store((const char*)sql_mode_str, sql_mode_len, scs); } - + if (et.expression) { String show_str; /* type */ sch_table->field[5]->store(STRING_WITH_LEN("RECURRING"), scs); - if (Events::reconstruct_interval_expression(&show_str, - et.interval, - et.expression)) + if (Events::reconstruct_interval_expression(&show_str, et.interval, + et.expression)) DBUG_RETURN(1); sch_table->field[7]->set_notnull(); @@ -4075,7 +4100,7 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) sch_table->field[8]->set_notnull(); sch_table->field[8]->store(ival->str, ival->length, scs); - //starts & ends + /* starts & ends */ sch_table->field[10]->set_notnull(); sch_table->field[10]->store_time(&et.starts, MYSQL_TIMESTAMP_DATETIME); @@ -4094,13 +4119,13 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) sch_table->field[6]->store_time(&et.execute_at, MYSQL_TIMESTAMP_DATETIME); } - //status + /* status */ if (et.status == Event_timed::ENABLED) sch_table->field[12]->store(STRING_WITH_LEN("ENABLED"), scs); else sch_table->field[12]->store(STRING_WITH_LEN("DISABLED"), scs); - //on_completion + /* on_completion */ if (et.on_completion == Event_timed::ON_COMPLETION_DROP) sch_table->field[13]->store(STRING_WITH_LEN("NOT PRESERVE"), scs); else @@ -4130,98 +4155,179 @@ fill_events_copy_to_schema_table(THD *thd, TABLE *sch_table, TABLE *event_table) } -int fill_schema_events(THD *thd, TABLE_LIST *tables, COND *cond) +/* + Performs an index scan of event_table (mysql.event) and fills schema_table. + + Synopsis + events_table_index_read_for_db() + thd Thread + schema_table The I_S.EVENTS table + event_table The event table to use for loading (mysql.event) + + Returns + 0 OK + 1 Error +*/ + +static +int events_table_index_read_for_db(THD *thd, TABLE *schema_table, + TABLE *event_table) { - 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; + CHARSET_INFO *scs= system_charset_info; + KEY *key_info; + uint key_len; 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)); + DBUG_ENTER("schema_events_do_index_scan"); - thd->reset_n_backup_open_tables_state(&backup); + DBUG_PRINT("info", ("Using prefix scanning on PK")); + event_table->file->ha_index_init(0, 1); + event_table->field[Events::FIELD_DB]-> + store(thd->lex->select_lex.db, strlen(thd->lex->select_lex.db), scs); + key_info= event_table->key_info; + key_len= key_info->key_part[0].store_length; - if ((ret= Events::open_event_table(thd, TL_READ, &event_table))) + if (!(key_buf= (byte *)alloc_root(thd->mem_root, key_len))) { - 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 !! */ - verbose= ((thd->lex->verbose || - thd->lex->orig_sql_command != SQLCOM_SHOW_EVENTS) && - (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; + /* don't send error, it would be done by sql_alloc_error_handler() */ } else { - event_table->field[Events::FIELD_DEFINER]-> - store(definer, strlen(definer), scs); - key_len= event_table->key_info->key_part[0].store_length; - - if (thd->lex->select_lex.db) + key_copy(key_buf, event_table->record[0], key_info, key_len); + if (!(ret= event_table->file->index_read(event_table->record[0], key_buf, + key_len, HA_READ_PREFIX))) { - event_table->field[Events::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= (byte *)alloc_root(thd->mem_root, key_len))) - { - ret= 1; - goto err; + DBUG_PRINT("info",("Found rows. Let's retrieve them. ret=%d", ret)); + do + { + ret= copy_event_to_schema_table(thd, schema_table, event_table); + if (ret == 0) + ret= event_table->file->index_next_same(event_table->record[0], + key_buf, key_len); + } while (ret == 0); } - - 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); + DBUG_PRINT("info", ("Scan finished. ret=%d", ret)); } + event_table->file->ha_index_end(); + /* ret is guaranteed to be != 0 */ + if (ret == HA_ERR_END_OF_FILE || ret == HA_ERR_KEY_NOT_FOUND) + DBUG_RETURN(0); + DBUG_RETURN(1); +} + + +/* + Performs a table scan of event_table (mysql.event) and fills schema_table. + + Synopsis + events_table_scan_all() + thd Thread + schema_table The I_S.EVENTS in memory table + event_table The event table to use for loading. - if (ret) + Returns + 0 OK + 1 Error +*/ + +static +int events_table_scan_all(THD *thd, TABLE *schema_table, + TABLE *event_table) +{ + int ret; + READ_RECORD read_record_info; + + DBUG_ENTER("schema_events_do_table_scan"); + init_read_record(&read_record_info, thd, event_table, NULL, 1, 0); + + /* + rr_sequential, in read_record(), returns 137==HA_ERR_END_OF_FILE, + but rr_handle_error returns -1 for that reason. Thus, read_record() + returns -1 eventually. + */ + do { - ret= (ret == HA_ERR_END_OF_FILE || ret == HA_ERR_KEY_NOT_FOUND) ? 0 : 1; - goto err; + ret= read_record_info.read_record(&read_record_info); + if (ret == 0) + ret= copy_event_to_schema_table(thd, schema_table, event_table); } + while (ret == 0); - while (!ret) - { - if ((ret= fill_events_copy_to_schema_table(thd, table, event_table))) - goto err; + DBUG_PRINT("info", ("Scan finished. ret=%d", ret)); + end_read_record(&read_record_info); - 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 */ + DBUG_RETURN(ret == -1? 0:1); +} + + +/* + Fills I_S.EVENTS with data loaded from mysql.event. Also used by + SHOW EVENTS + + Synopsis + fill_schema_events() + thd Thread + tables The schema table + cond Unused + + Returns + 0 OK + 1 Error +*/ + +int fill_schema_events(THD *thd, TABLE_LIST *tables, COND * /* cond */) +{ + TABLE *schema_table= tables->table; + TABLE *event_table= NULL; + Open_tables_state backup; + int ret= 0; + + DBUG_ENTER("fill_schema_events"); + /* + If it's SHOW EVENTS then thd->lex->select_lex.db is guaranteed not to + be NULL. Let's do an assert anyway. + */ + if (thd->lex->orig_sql_command == SQLCOM_SHOW_EVENTS) + { + DBUG_ASSERT(thd->lex->select_lex.db); + if (check_access(thd, EVENT_ACL, thd->lex->select_lex.db, 0, 0, 0, + is_schema_db(thd->lex->select_lex.db))) + DBUG_RETURN(1); } - // ret is guaranteed to be != 0 - ret= (ret != HA_ERR_END_OF_FILE); -err: - if (event_table) + + DBUG_PRINT("info",("db=%s", thd->lex->select_lex.db? + thd->lex->select_lex.db:"(null)")); + + thd->reset_n_backup_open_tables_state(&backup); + if (Events::open_event_table(thd, TL_READ, &event_table)) { - event_table->file->ha_index_end(); - close_thread_tables(thd); + sql_print_error("Table mysql.event is damaged."); + thd->restore_backup_open_tables_state(&backup); + DBUG_RETURN(1); } + /* + 1. SELECT I_S => use table scan. I_S.EVENTS does not guarantee order + thus we won't order it. OTOH, SHOW EVENTS will be + ordered. + 2. SHOW EVENTS => PRIMARY KEY with prefix scanning on (db) + Reasoning: Events are per schema, therefore a scan over an index + will save use from doing a table scan and comparing + every single row's `db` with the schema which we show. + */ + if (thd->lex->orig_sql_command == SQLCOM_SHOW_EVENTS) + ret= events_table_index_read_for_db(thd, schema_table, event_table); + else + ret= events_table_scan_all(thd, schema_table, event_table); + + close_thread_tables(thd); thd->restore_backup_open_tables_state(&backup); + + DBUG_PRINT("info", ("Return code=%d", ret)); DBUG_RETURN(ret); } |