Commit 750c4022 authored by hezx@mail.hezx.com's avatar hezx@mail.hezx.com
Browse files

BUG#33862 completely failed DROP USER statement gets replicated

The problem is when create/rename/drop users, the statement was logged regardless of error, even if no data has been changed, the statement was logged.

After this patch, create/rename/drop users don't write the binlog if the statement makes no changes, if the statement does make any changes, log the statement with possible error code.

This patch is based on the patch for BUG#29749, which is not pushed
parent 87abfe06
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
stop slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
reset master;
reset slave;
drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
start slave;
reset master;
delete from mysql.user where Host='fakehost';
create user 'foo'@'fakehost';
create user 'foo'@'fakehost', 'bar'@'fakehost';
ERROR HY000: Operation CREATE USER failed for 'foo'@'fakehost'
create user 'foo'@'fakehost', 'bar'@'fakehost';
ERROR HY000: Operation CREATE USER failed for 'foo'@'fakehost','bar'@'fakehost'
select Host,User from mysql.user where Host='fakehost';
Host	User
fakehost	bar
fakehost	foo
rename user 'foo'@'fakehost' to 'foofoo'@'fakehost';
rename user 'not_exist_user1'@'fakehost' to 'foobar'@'fakehost', 'bar'@'fakehost' to 'barbar'@'fakehost';
ERROR HY000: Operation RENAME USER failed for 'not_exist_user1'@'fakehost'
rename user 'not_exist_user1'@'fakehost' to 'foobar'@'fakehost', 'not_exist_user2'@'fakehost' to 'barfoo'@'fakehost';
ERROR HY000: Operation RENAME USER failed for 'not_exist_user1'@'fakehost','not_exist_user2'@'fakehost'
select Host,User from mysql.user where Host='fakehost';
Host	User
fakehost	barbar
fakehost	foofoo
drop user 'foofoo'@'fakehost';
drop user 'not_exist_user1'@'fakehost', 'barbar'@'fakehost';
ERROR HY000: Operation DROP USER failed for 'not_exist_user1'@'fakehost'
drop user 'not_exist_user1'@'fakehost', 'not_exist_user2'@'fakehost';
ERROR HY000: Operation DROP USER failed for 'not_exist_user1'@'fakehost','not_exist_user2'@'fakehost'
select Host,User from mysql.user where Host='fakehost';
Host	User
show binlog events from 98;
Log_name	Pos	Event_type	Server_id	End_log_pos	Info
master-bin.000001	98	Query	1	#	use `test`; delete from mysql.user where Host='fakehost'
master-bin.000001	205	Query	1	#	use `test`; create user 'foo'@'fakehost'
master-bin.000001	296	Query	1	#	use `test`; create user 'foo'@'fakehost', 'bar'@'fakehost'
master-bin.000001	405	Query	1	#	use `test`; rename user 'foo'@'fakehost' to 'foofoo'@'fakehost'
master-bin.000001	519	Query	1	#	use `test`; rename user 'not_exist_user1'@'fakehost' to 'foobar'@'fakehost', 'bar'@'fakehost' to 'barbar'@'fakehost'
master-bin.000001	686	Query	1	#	use `test`; drop user 'foofoo'@'fakehost'
master-bin.000001	778	Query	1	#	use `test`; drop user 'not_exist_user1'@'fakehost', 'barbar'@'fakehost'
+56 −0
Original line number Diff line number Diff line
# BUG#33862 completely failed DROP USER statement gets replicated

--source include/master-slave.inc

reset master;

#
# remove all users will be used in the test
#
delete from mysql.user where Host='fakehost';
sync_slave_with_master;

#
# Test create user
#
connection master;
create user 'foo'@'fakehost';
--error ER_CANNOT_USER
create user 'foo'@'fakehost', 'bar'@'fakehost';
--error ER_CANNOT_USER
create user 'foo'@'fakehost', 'bar'@'fakehost';

sync_slave_with_master;
select Host,User from mysql.user where Host='fakehost';

#
# Test rename user
#
connection master;
rename user 'foo'@'fakehost' to 'foofoo'@'fakehost';
--error ER_CANNOT_USER
rename user 'not_exist_user1'@'fakehost' to 'foobar'@'fakehost', 'bar'@'fakehost' to 'barbar'@'fakehost';
--error ER_CANNOT_USER
rename user 'not_exist_user1'@'fakehost' to 'foobar'@'fakehost', 'not_exist_user2'@'fakehost' to 'barfoo'@'fakehost';

sync_slave_with_master;
select Host,User from mysql.user where Host='fakehost';

#
# Test drop user
#
connection master;
drop user 'foofoo'@'fakehost';
--error ER_CANNOT_USER
drop user 'not_exist_user1'@'fakehost', 'barbar'@'fakehost';
--error ER_CANNOT_USER
drop user 'not_exist_user1'@'fakehost', 'not_exist_user2'@'fakehost';

sync_slave_with_master;
select Host,User from mysql.user where Host='fakehost';

#
# show the binlog events on the master
#
connection master;
source include/show_binlog_events.inc;
+17 −7
Original line number Diff line number Diff line
@@ -5333,6 +5333,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
  LEX_USER *user_name, *tmp_user_name;
  List_iterator <LEX_USER> user_list(list);
  TABLE_LIST tables[GRANT_TABLES];
  bool some_users_created= FALSE;
  DBUG_ENTER("mysql_create_user");

  /* CREATE USER may be skipped on replication client. */
@@ -5361,6 +5362,7 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)
      continue;
    }

    some_users_created= TRUE;
    sql_mode= thd->variables.sql_mode;
    if (replace_user_table(thd, tables[0].table, *user_name, 0, 0, 1, 0))
    {
@@ -5371,7 +5373,10 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)

  VOID(pthread_mutex_unlock(&acl_cache->lock));

  if (mysql_bin_log.is_open())
  if (result)
    my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe());

  if (some_users_created && mysql_bin_log.is_open())
  {
    Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
    mysql_bin_log.write(&qinfo);
@@ -5379,8 +5384,6 @@ bool mysql_create_user(THD *thd, List <LEX_USER> &list)

  rw_unlock(&LOCK_grant);
  close_thread_tables(thd);
  if (result)
    my_error(ER_CANNOT_USER, MYF(0), "CREATE USER", wrong_users.c_ptr_safe());
  DBUG_RETURN(result);
}

@@ -5405,6 +5408,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
  LEX_USER *user_name, *tmp_user_name;
  List_iterator <LEX_USER> user_list(list);
  TABLE_LIST tables[GRANT_TABLES];
  bool some_users_deleted= FALSE;
  DBUG_ENTER("mysql_drop_user");

  /* DROP USER may be skipped on replication client. */
@@ -5426,7 +5430,9 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
    {
      append_user(&wrong_users, user_name);
      result= TRUE;
      continue;
    }
    some_users_deleted= TRUE;
  }

  /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
@@ -5440,7 +5446,7 @@ bool mysql_drop_user(THD *thd, List <LEX_USER> &list)
  DBUG_PRINT("info", ("thd->net.last_errno: %d", thd->net.last_errno));
  DBUG_PRINT("info", ("thd->net.last_error: %s", thd->net.last_error));

  if (mysql_bin_log.is_open())
  if (some_users_deleted && mysql_bin_log.is_open())
  {
    Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
    mysql_bin_log.write(&qinfo);
@@ -5473,6 +5479,7 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
  LEX_USER *user_to, *tmp_user_to;
  List_iterator <LEX_USER> user_list(list);
  TABLE_LIST tables[GRANT_TABLES];
  bool some_users_renamed= FALSE;
  DBUG_ENTER("mysql_rename_user");

  /* RENAME USER may be skipped on replication client. */
@@ -5506,7 +5513,9 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
    {
      append_user(&wrong_users, user_from);
      result= TRUE;
      continue;
    }
    some_users_renamed= TRUE;
  }
  
  /* Rebuild 'acl_check_hosts' since 'acl_users' has been modified */
@@ -5514,7 +5523,10 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)

  VOID(pthread_mutex_unlock(&acl_cache->lock));

  if (mysql_bin_log.is_open())
  if (result)
    my_error(ER_CANNOT_USER, MYF(0), "RENAME USER", wrong_users.c_ptr_safe());
  
  if (some_users_renamed && mysql_bin_log.is_open())
  {
    Query_log_event qinfo(thd, thd->query, thd->query_length, 0, FALSE);
    mysql_bin_log.write(&qinfo);
@@ -5522,8 +5534,6 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)

  rw_unlock(&LOCK_grant);
  close_thread_tables(thd);
  if (result)
    my_error(ER_CANNOT_USER, MYF(0), "RENAME USER", wrong_users.c_ptr_safe());
  DBUG_RETURN(result);
}