Below is the list of changes that have just been committed into a local
5.1 repository of alik. When alik does a push these changes will
be propagated to the main repository and, within 24 hours after the
push, to the public repository.
For information on how to access the public repository
see http://dev.mysql.com/doc/mysql/en/installing-source-tree.html
ChangeSet@stripped, 2007-10-17 10:05:50+04:00, anozdrin@station. +7 -0
Patch for BUG#31111: --read-only crashes MySQL (events fail to load).
There actually were several problems here:
- WRITE-lock is required to load events from the mysql.event table,
but in the read-only mode an ordinary user can not acquire it;
- Security_context::master_access attribute was not properly
initialized in Security_context::init(), which led to differences
in behavior with and without debug configure options.
- if the server failed to load events from mysql.event, it:
- forgot to close the mysql.event table, that led to the coredump,
described in the bug report;
- did not deinitialize the replication module, that lead to
memory-lost warning on exit.
The patch is to fix all these problems:
- Use the super-user to acquire WRITE-lock on the mysql.even table;
- The WRITE-lock is acquired by the event scheduler in two cases:
- on initial loading of events from the database;
- when an event has been executed, so its attributes should
be updated.
Other cases when WRITE-lock is needed for the mysql.event table
happen under the user account. So, nothing should be changed there:
The user is able to create/update/drop an event only if he is
a super-user.
- Initialize Security_context::master_access;
- Close the mysql.event table in case something went wrong;
- Deinitialize the replication module on exit.
mysql-test/r/bug31111.result@stripped, 2007-10-17 10:05:48+04:00, anozdrin@station. +53 -0
Result file.
mysql-test/r/bug31111.result@stripped, 2007-10-17 10:05:48+04:00, anozdrin@station. +0 -0
mysql-test/t/bug31111-master.opt@stripped, 2007-10-17 10:05:48+04:00, anozdrin@station. +1 -0
A test case for BUG#31111.
mysql-test/t/bug31111-master.opt@stripped, 2007-10-17 10:05:48+04:00, anozdrin@station. +0 -0
mysql-test/t/bug31111.test@stripped, 2007-10-17 10:05:48+04:00, anozdrin@station. +101 -0
A test case for BUG#31111.
mysql-test/t/bug31111.test@stripped, 2007-10-17 10:05:48+04:00, anozdrin@station. +0 -0
sql/event_db_repository.cc@stripped, 2007-10-17 10:05:48+04:00, anozdrin@station. +23 -3
1. Close tables if something went wrong in simple_open_n_lock_tables();
2. Open the mysql.event table as the super user to be able to acquire
WRITE-lock in the read-only mode.
sql/events.cc@stripped, 2007-10-17 10:05:48+04:00, anozdrin@station. +15 -1
Open the mysql.event table as the super user to be able to acquire
WRITE-lock in the read-only mode.
sql/mysqld.cc@stripped, 2007-10-17 10:05:48+04:00, anozdrin@station. +3 -0
If something went wrong with event loading, we the replication
module should be deinitialized prior to general exit procedure.
sql/sql_class.cc@stripped, 2007-10-17 10:05:48+04:00, anozdrin@station. +1 -0
Initialize Security_context::master_acces.
diff -Nrup a/mysql-test/r/bug31111.result b/mysql-test/r/bug31111.result
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/mysql-test/r/bug31111.result 2007-10-17 10:05:48 +04:00
@@ -0,0 +1,53 @@
+SELECT @@global.read_only;
+@@global.read_only
+1
+
+GRANT EVENT ON *.* TO u1@localhost;
+
+#
+# Connection: con1 (u1@localhost/test).
+#
+
+CREATE EVENT e1 ON SCHEDULE AT '2020-01-01 00:00:00' DO SET @a = 1;
+ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement
+
+ALTER EVENT e1 COMMENT 'comment';
+ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement
+
+DROP EVENT e1;
+ERROR HY000: The MySQL server is running with the --read-only option so it cannot execute this statement
+
+#
+# Connection: default.
+#
+
+CREATE EVENT e1 ON SCHEDULE AT '2020-01-01 00:00:00' DO SET @a = 1;
+
+ALTER EVENT e1 COMMENT 'comment';
+
+DROP EVENT e1;
+
+CREATE EVENT e1 ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 SECOND DO SET @a = 1;
+CREATE EVENT e2 ON SCHEDULE EVERY 1 SECOND DO SET @a = 1;
+
+SELECT name, last_executed IS NULL FROM mysql.event;
+name last_executed IS NULL
+e1 1
+e2 1
+
+SET GLOBAL EVENT_SCHEDULER = ON;
+
+# Sleeping for 3 seconds...
+
+SELECT name, last_executed IS NULL FROM mysql.event;
+name last_executed IS NULL
+e2 0
+
+SET GLOBAL EVENT_SCHEDULER = OFF;
+
+DROP EVENT e1;
+ERROR HY000: Unknown event 'e1'
+
+DROP EVENT e2;
+
+# That is it.
diff -Nrup a/mysql-test/t/bug31111-master.opt b/mysql-test/t/bug31111-master.opt
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/mysql-test/t/bug31111-master.opt 2007-10-17 10:05:48 +04:00
@@ -0,0 +1 @@
+--read-only
diff -Nrup a/mysql-test/t/bug31111.test b/mysql-test/t/bug31111.test
--- /dev/null Wed Dec 31 16:00:00 196900
+++ b/mysql-test/t/bug31111.test 2007-10-17 10:05:48 +04:00
@@ -0,0 +1,101 @@
+#
+# BUG#31111: --read-only crashes MySQL (events fail to load).
+#
+# It actually does not matter what SQL statements are here. The thing is being
+# tested is that the server is able to start.
+#
+
+SELECT @@global.read_only;
+
+--echo
+
+# Check that an ordinary user can not create/update/drop events.
+
+GRANT EVENT ON *.* TO u1@localhost;
+
+--echo
+
+--echo #
+--echo # Connection: con1 (u1@localhost/test).
+--echo #
+
+--connect(con1,localhost,u1,,test)
+
+--echo
+
+--error ER_OPTION_PREVENTS_STATEMENT
+CREATE EVENT e1 ON SCHEDULE AT '2020-01-01 00:00:00' DO SET @a = 1;
+
+--echo
+
+--error ER_OPTION_PREVENTS_STATEMENT
+ALTER EVENT e1 COMMENT 'comment';
+
+--echo
+
+--error ER_OPTION_PREVENTS_STATEMENT
+DROP EVENT e1;
+
+--echo
+
+--disconnect con1
+
+--echo #
+--echo # Connection: default.
+--echo #
+
+--connection default
+
+# Check that the super user still can create/update/drop events.
+
+--echo
+
+CREATE EVENT e1 ON SCHEDULE AT '2020-01-01 00:00:00' DO SET @a = 1;
+
+--echo
+
+ALTER EVENT e1 COMMENT 'comment';
+
+--echo
+
+DROP EVENT e1;
+
+--echo
+
+# Check that the scheduler is able to update event.
+
+CREATE EVENT e1 ON SCHEDULE AT CURRENT_TIMESTAMP + INTERVAL 1 SECOND DO SET @a = 1;
+CREATE EVENT e2 ON SCHEDULE EVERY 1 SECOND DO SET @a = 1;
+
+--echo
+
+SELECT name, last_executed IS NULL FROM mysql.event;
+
+--echo
+
+SET GLOBAL EVENT_SCHEDULER = ON;
+
+--echo
+
+--echo # Sleeping for 3 seconds...
+--sleep 3
+
+--echo
+
+SELECT name, last_executed IS NULL FROM mysql.event;
+
+--echo
+
+SET GLOBAL EVENT_SCHEDULER = OFF;
+
+--echo
+
+--error ER_EVENT_DOES_NOT_EXIST
+DROP EVENT e1;
+
+--echo
+
+DROP EVENT e2;
+
+--echo
+--echo # That is it.
diff -Nrup a/sql/event_db_repository.cc b/sql/event_db_repository.cc
--- a/sql/event_db_repository.cc 2007-08-25 12:43:10 +04:00
+++ b/sql/event_db_repository.cc 2007-10-17 10:05:48 +04:00
@@ -525,6 +525,9 @@ Event_db_repository::fill_schema_events(
- whether this open mode would work under LOCK TABLES, or inside a
stored function or trigger.
+ Note, if the table can not be open, this operation will clean out all
+ table-related objects from the memory.
+
@param[in] thd Thread context
@param[in] lock_type How to lock the table
@param[out] table We will store the open table here
@@ -544,7 +547,10 @@ Event_db_repository::open_event_table(TH
tables.init_one_table("mysql", "event", lock_type);
if (simple_open_n_lock_tables(thd, &tables))
+ {
+ close_thread_tables(thd, FALSE, FALSE);
DBUG_RETURN(TRUE);
+ }
*table= tables.table;
tables.table->use_all_columns();
@@ -984,7 +990,8 @@ update_timing_fields_for_event(THD *thd,
{
TABLE *table= NULL;
Field **fields;
- int ret= 1;
+ bool ret= TRUE;
+ ulong saved_master_access;
DBUG_ENTER("Event_db_repository::update_timing_fields_for_event");
@@ -995,7 +1002,20 @@ update_timing_fields_for_event(THD *thd,
if (thd->current_stmt_binlog_row_based)
thd->clear_current_stmt_binlog_row_based();
- if (open_event_table(thd, TL_WRITE, &table))
+ /*
+ NOTE: even if we run in read-only mode, we should be able to lock the
+ mysql.event table for writing. In order to achieve this, we should call
+ mysql_lock_tables() under the super user.
+ */
+
+ saved_master_access= thd->security_ctx->master_access;
+ thd->security_ctx->master_access |= SUPER_ACL;
+
+ ret= open_event_table(thd, TL_WRITE, &table);
+
+ thd->security_ctx->master_access= saved_master_access;
+
+ if (ret)
goto end;
fields= table->field;
@@ -1028,7 +1048,7 @@ update_timing_fields_for_event(THD *thd,
goto end;
}
- ret= 0;
+ ret= FALSE;
end:
if (table)
diff -Nrup a/sql/events.cc b/sql/events.cc
--- a/sql/events.cc 2007-08-15 19:08:40 +04:00
+++ b/sql/events.cc 2007-10-17 10:05:48 +04:00
@@ -1124,11 +1124,25 @@ Events::load_events_from_db(THD *thd)
READ_RECORD read_record_info;
bool ret= TRUE;
uint count= 0;
+ ulong saved_master_access;
DBUG_ENTER("Events::load_events_from_db");
DBUG_PRINT("enter", ("thd: 0x%lx", (long) thd));
- if (db_repository->open_event_table(thd, TL_WRITE, &table))
+ /*
+ NOTE: even if we run in read-only mode, we should be able to lock the
+ mysql.event table for writing. In order to achieve this, we should call
+ mysql_lock_tables() under the super user.
+ */
+
+ saved_master_access= thd->security_ctx->master_access;
+ thd->security_ctx->master_access |= SUPER_ACL;
+
+ ret= db_repository->open_event_table(thd, TL_WRITE, &table);
+
+ thd->security_ctx->master_access= saved_master_access;
+
+ if (ret)
{
sql_print_error("Event Scheduler: Failed to open table mysql.event");
DBUG_RETURN(TRUE);
diff -Nrup a/sql/mysqld.cc b/sql/mysqld.cc
--- a/sql/mysqld.cc 2007-08-28 11:02:53 +04:00
+++ b/sql/mysqld.cc 2007-10-17 10:05:48 +04:00
@@ -3930,7 +3930,10 @@ we force server id to 2, but this MySQL
create_maintenance_thread();
if (Events::init(opt_noacl))
+ {
+ end_slave();
unireg_abort(1);
+ }
sql_print_information(ER(ER_STARTUP),my_progname,server_version,
((unix_sock == INVALID_SOCKET) ? (char*) ""
diff -Nrup a/sql/sql_class.cc b/sql/sql_class.cc
--- a/sql/sql_class.cc 2007-10-15 16:42:39 +04:00
+++ b/sql/sql_class.cc 2007-10-17 10:05:48 +04:00
@@ -2404,6 +2404,7 @@ void Security_context::init()
host= user= priv_user= ip= 0;
host_or_ip= "connecting host";
priv_host[0]= '\0';
+ master_access= 0;
#ifndef NO_EMBEDDED_ACCESS_CHECKS
db_access= NO_ACCESS;
#endif
| Thread |
|---|
| • bk commit into 5.1 tree (anozdrin:1.2600) BUG#31111 | Alexander Nozdrin | 17 Oct |