From 750c4022f23176c721bf41ad8cfb3ac14d048d7c Mon Sep 17 00:00:00 2001 From: "hezx@mail.hezx.com" <> Date: Fri, 25 Jan 2008 15:02:26 +0800 Subject: [PATCH] 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 --- mysql-test/r/rpl_user.result | 42 +++++++++++++++++++++++++++ mysql-test/t/rpl_user.test | 56 ++++++++++++++++++++++++++++++++++++ sql/sql_acl.cc | 24 +++++++++++----- 3 files changed, 115 insertions(+), 7 deletions(-) create mode 100644 mysql-test/r/rpl_user.result create mode 100644 mysql-test/t/rpl_user.test diff --git a/mysql-test/r/rpl_user.result b/mysql-test/r/rpl_user.result new file mode 100644 index 00000000000..475579e7d33 --- /dev/null +++ b/mysql-test/r/rpl_user.result @@ -0,0 +1,42 @@ +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' diff --git a/mysql-test/t/rpl_user.test b/mysql-test/t/rpl_user.test new file mode 100644 index 00000000000..8c85b1e9249 --- /dev/null +++ b/mysql-test/t/rpl_user.test @@ -0,0 +1,56 @@ +# 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; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index 1850821a287..a5140d6f7d0 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -5333,6 +5333,7 @@ bool mysql_create_user(THD *thd, List &list) LEX_USER *user_name, *tmp_user_name; List_iterator 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 &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 &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 &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 &list) LEX_USER *user_name, *tmp_user_name; List_iterator 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 &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 &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 &list) LEX_USER *user_to, *tmp_user_to; List_iterator 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 &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 &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 &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); }