mirror of
https://github.com/MariaDB/server.git
synced 2025-08-30 11:22:14 +03:00
Bug #14262: SP: DROP PROCEDURE|VIEW (maybe more) write to binlog too late \
(race cond) It was possible for one thread to interrupt a Data Definition Language statement and thereby get messages to the binlog out of order. Consider: Connection 1: Drop Foo x Connection 2: Create or replace Foo x Connection 2: Log "Create or replace Foo x" Connection 1: Log "Drop Foo x" Local end would have Foo x, but the replicated slaves would not. The fix for this is to wrap all DDL and logging of a kind in the same mutex. Since we already use mutexes for the various parts of altering the server, this only entails moving the logging events down close to the action, inside the mutex protection. BitKeeper/etc/collapsed: BitKeeper file /home/cmiller/work/mysql/bug14262/my50-bug14262/BitKeeper/etc/collapsed --- BitKeeper file /home/cmiller/work/mysql/bug14262/my50-bug14262/BitKeeper/etc/collapsed --- BitKeeper file /home/cmiller/work/mysql/bug14262/my50-bug14262/BitKeeper/etc/collapsed --- BitKeeper file /home/cmiller/work/mysql/bug14262/my50-bug14262/BitKeeper/etc/collapsed --- BitKeeper file /home/cmiller/work/mysql/bug14262/my50-bug14262/BitKeeper/etc/collapsed --- BitKeeper file /home/cmiller/work/mysql/bug14262/my50-bug14262/BitKeeper/etc/collapsed --- BitKeeper file /home/cmiller/work/mysql/bug14262/my50-bug14262/BitKeeper/etc/collapsed --- BitKeeper file /home/cmiller/work/mysql/bug14262/my50-bug14262/BitKeeper/etc/collapsed sql/sp.cc: Move logging inside the routine drop and update functions, so it can be protected by a LOCK_open mutex. (The "create" function already had such a LOCK_open protection.) sql/sql_acl.cc: Move logging inside the grant functions, so that it can be protected by LOCK_grant . sql/sql_db.cc: Add comments that describe how each logging event is protected. sql/sql_parse.cc: Move all logging statements about DDL statements close to the actual event, so each can be protected by the same mutex. sql/sql_table.cc: Widen the scope of the mutex so that logging events are also protected. sql/sql_trigger.cc: Widen the scope of the mutex so that logging events are also protected. sql/sql_view.cc: Pass the head of the table linked-list so we can create a logging statement. Move the logging statement inside the worker function, and notably inside the LOCK_open mutex. Widen the same mutex a little to make room for logging. sql/sql_view.h: Pass the head of the table linked-list so we can create a logging statement.
This commit is contained in:
118
sql/sql_parse.cc
118
sql/sql_parse.cc
@@ -3195,6 +3195,7 @@ end_with_restore_list:
|
||||
/* ! we write after unlocking the table */
|
||||
if (!res && !lex->no_write_to_binlog)
|
||||
{
|
||||
/* Presumably, REPAIR and binlog writing doesn't require synchronization */
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
thd->clear_error(); // No binlog error generated
|
||||
@@ -3229,6 +3230,7 @@ end_with_restore_list:
|
||||
/* ! we write after unlocking the table */
|
||||
if (!res && !lex->no_write_to_binlog)
|
||||
{
|
||||
/* Presumably, ANALYZE and binlog writing doesn't require synchronization */
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
thd->clear_error(); // No binlog error generated
|
||||
@@ -3254,6 +3256,7 @@ end_with_restore_list:
|
||||
/* ! we write after unlocking the table */
|
||||
if (!res && !lex->no_write_to_binlog)
|
||||
{
|
||||
/* Presumably, OPTIMIZE and binlog writing doesn't require synchronization */
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
thd->clear_error(); // No binlog error generated
|
||||
@@ -3542,6 +3545,7 @@ end_with_restore_list:
|
||||
/* So that DROP TEMPORARY TABLE gets to binlog at commit/rollback */
|
||||
thd->options|= OPTION_STATUS_NO_TRANS_UPDATE;
|
||||
}
|
||||
/* DDL and binlog write order protected by LOCK_open */
|
||||
res= mysql_rm_table(thd, first_table, lex->drop_if_exists,
|
||||
lex->drop_temporary);
|
||||
}
|
||||
@@ -3830,15 +3834,9 @@ end_with_restore_list:
|
||||
break;
|
||||
if (end_active_trans(thd))
|
||||
goto error;
|
||||
/* Conditionally writes to binlog */
|
||||
if (!(res= mysql_create_user(thd, lex->users_list)))
|
||||
{
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
send_ok(thd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLCOM_DROP_USER:
|
||||
@@ -3848,15 +3846,9 @@ end_with_restore_list:
|
||||
break;
|
||||
if (end_active_trans(thd))
|
||||
goto error;
|
||||
/* Conditionally writes to binlog */
|
||||
if (!(res= mysql_drop_user(thd, lex->users_list)))
|
||||
{
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
send_ok(thd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLCOM_RENAME_USER:
|
||||
@@ -3866,15 +3858,9 @@ end_with_restore_list:
|
||||
break;
|
||||
if (end_active_trans(thd))
|
||||
goto error;
|
||||
/* Conditionally writes to binlog */
|
||||
if (!(res= mysql_rename_user(thd, lex->users_list)))
|
||||
{
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
send_ok(thd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLCOM_REVOKE_ALL:
|
||||
@@ -3882,15 +3868,9 @@ end_with_restore_list:
|
||||
if (check_access(thd, UPDATE_ACL, "mysql", 0, 1, 1, 0) &&
|
||||
check_global_access(thd,CREATE_USER_ACL))
|
||||
break;
|
||||
/* Conditionally writes to binlog */
|
||||
if (!(res = mysql_revoke_all(thd, lex->users_list)))
|
||||
{
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
send_ok(thd);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SQLCOM_REVOKE:
|
||||
@@ -3949,6 +3929,7 @@ end_with_restore_list:
|
||||
check_grant_routine(thd, grants | GRANT_ACL, all_tables,
|
||||
lex->type == TYPE_ENUM_PROCEDURE, 0))
|
||||
goto error;
|
||||
/* Conditionally writes to binlog */
|
||||
res= mysql_routine_grant(thd, all_tables,
|
||||
lex->type == TYPE_ENUM_PROCEDURE,
|
||||
lex->users_list, grants,
|
||||
@@ -3961,16 +3942,11 @@ end_with_restore_list:
|
||||
GRANT_ACL),
|
||||
all_tables, 0, UINT_MAX, 0))
|
||||
goto error;
|
||||
/* Conditionally writes to binlog */
|
||||
res= mysql_table_grant(thd, all_tables, lex->users_list,
|
||||
lex->columns, lex->grant,
|
||||
lex->sql_command == SQLCOM_REVOKE);
|
||||
}
|
||||
if (!res && mysql_bin_log.is_open())
|
||||
{
|
||||
thd->clear_error();
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -3981,16 +3957,11 @@ end_with_restore_list:
|
||||
goto error;
|
||||
}
|
||||
else
|
||||
/* Conditionally writes to binlog */
|
||||
res = mysql_grant(thd, select_lex->db, lex->users_list, lex->grant,
|
||||
lex->sql_command == SQLCOM_REVOKE);
|
||||
if (!res)
|
||||
{
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
thd->clear_error();
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
if (lex->sql_command == SQLCOM_GRANT)
|
||||
{
|
||||
List_iterator <LEX_USER> str_list(lex->users_list);
|
||||
@@ -4028,6 +3999,7 @@ end_with_restore_list:
|
||||
We WANT to write and we CAN write.
|
||||
! we write after unlocking the table.
|
||||
*/
|
||||
/* Presumably, RESET and binlog writing doesn't require synchronization */
|
||||
if (!lex->no_write_to_binlog && write_to_binlog)
|
||||
{
|
||||
if (mysql_bin_log.is_open())
|
||||
@@ -4564,20 +4536,16 @@ end_with_restore_list:
|
||||
already puts on CREATE FUNCTION.
|
||||
*/
|
||||
if (lex->sql_command == SQLCOM_ALTER_PROCEDURE)
|
||||
/* Conditionally writes to binlog */
|
||||
result= sp_update_procedure(thd, lex->spname, &lex->sp_chistics);
|
||||
else
|
||||
/* Conditionally writes to binlog */
|
||||
result= sp_update_function(thd, lex->spname, &lex->sp_chistics);
|
||||
}
|
||||
}
|
||||
switch (result)
|
||||
{
|
||||
case SP_OK:
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
thd->clear_error();
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
send_ok(thd);
|
||||
break;
|
||||
case SP_KEY_NOT_FOUND:
|
||||
@@ -4622,9 +4590,11 @@ end_with_restore_list:
|
||||
}
|
||||
#endif
|
||||
if (lex->sql_command == SQLCOM_DROP_PROCEDURE)
|
||||
result= sp_drop_procedure(thd, lex->spname);
|
||||
/* Conditionally writes to binlog */
|
||||
result= sp_drop_procedure(thd, lex->spname); /* Conditionally writes to binlog */
|
||||
else
|
||||
result= sp_drop_function(thd, lex->spname);
|
||||
/* Conditionally writes to binlog */
|
||||
result= sp_drop_function(thd, lex->spname); /* Conditionally writes to binlog */
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -4637,6 +4607,8 @@ end_with_restore_list:
|
||||
{
|
||||
if (check_access(thd, DELETE_ACL, "mysql", 0, 1, 0, 0))
|
||||
goto error;
|
||||
|
||||
/* Does NOT write to binlog */
|
||||
if (!(res = mysql_drop_function(thd, &lex->spname->m_name)))
|
||||
{
|
||||
send_ok(thd);
|
||||
@@ -4657,12 +4629,6 @@ end_with_restore_list:
|
||||
switch (result)
|
||||
{
|
||||
case SP_OK:
|
||||
if (mysql_bin_log.is_open())
|
||||
{
|
||||
thd->clear_error();
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
send_ok(thd);
|
||||
break;
|
||||
case SP_KEY_NOT_FOUND:
|
||||
@@ -4758,37 +4724,8 @@ end_with_restore_list:
|
||||
{
|
||||
if (end_active_trans(thd))
|
||||
goto error;
|
||||
|
||||
if (!(res= mysql_create_view(thd, thd->lex->create_view_mode)) &&
|
||||
mysql_bin_log.is_open())
|
||||
{
|
||||
String buff;
|
||||
const LEX_STRING command[3]=
|
||||
{{(char *)STRING_WITH_LEN("CREATE ")},
|
||||
{(char *)STRING_WITH_LEN("ALTER ")},
|
||||
{(char *)STRING_WITH_LEN("CREATE OR REPLACE ")}};
|
||||
thd->clear_error();
|
||||
|
||||
buff.append(command[thd->lex->create_view_mode].str,
|
||||
command[thd->lex->create_view_mode].length);
|
||||
view_store_options(thd, first_table, &buff);
|
||||
buff.append(STRING_WITH_LEN("VIEW "));
|
||||
/* Test if user supplied a db (ie: we did not use thd->db) */
|
||||
if (first_table->db && first_table->db[0] &&
|
||||
(thd->db == NULL || strcmp(first_table->db, thd->db)))
|
||||
{
|
||||
append_identifier(thd, &buff, first_table->db,
|
||||
first_table->db_length);
|
||||
buff.append('.');
|
||||
}
|
||||
append_identifier(thd, &buff, first_table->table_name,
|
||||
first_table->table_name_length);
|
||||
buff.append(STRING_WITH_LEN(" AS "));
|
||||
buff.append(first_table->source.str, first_table->source.length);
|
||||
|
||||
Query_log_event qinfo(thd, buff.ptr(), buff.length(), 0, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
/* Conditionally writes to binlog. */
|
||||
res= mysql_create_view(thd, first_table, thd->lex->create_view_mode);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_DROP_VIEW:
|
||||
@@ -4796,13 +4733,8 @@ end_with_restore_list:
|
||||
if (check_table_access(thd, DROP_ACL, all_tables, 0) ||
|
||||
end_active_trans(thd))
|
||||
goto error;
|
||||
if (!(res= mysql_drop_view(thd, first_table, thd->lex->drop_mode)) &&
|
||||
mysql_bin_log.is_open())
|
||||
{
|
||||
thd->clear_error();
|
||||
Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
|
||||
mysql_bin_log.write(&qinfo);
|
||||
}
|
||||
/* Conditionally writes to binlog. */
|
||||
res= mysql_drop_view(thd, first_table, thd->lex->drop_mode);
|
||||
break;
|
||||
}
|
||||
case SQLCOM_CREATE_TRIGGER:
|
||||
@@ -4810,6 +4742,7 @@ end_with_restore_list:
|
||||
if (end_active_trans(thd))
|
||||
goto error;
|
||||
|
||||
/* Conditionally writes to binlog. */
|
||||
res= mysql_create_or_drop_trigger(thd, all_tables, 1);
|
||||
|
||||
/* We don't care about trigger body after this point */
|
||||
@@ -4822,6 +4755,7 @@ end_with_restore_list:
|
||||
if (end_active_trans(thd))
|
||||
goto error;
|
||||
|
||||
/* Conditionally writes to binlog. */
|
||||
res= mysql_create_or_drop_trigger(thd, all_tables, 0);
|
||||
break;
|
||||
}
|
||||
|
Reference in New Issue
Block a user