diff --git a/mysql-test/r/rpl_do_grant.result b/mysql-test/r/rpl_do_grant.result new file mode 100644 index 00000000000..fec935ae7ac --- /dev/null +++ b/mysql-test/r/rpl_do_grant.result @@ -0,0 +1,26 @@ +slave stop; +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; +slave start; +delete from mysql.user where user='rpl_do_grant'; +delete from mysql.db where user='rpl_do_grant'; +flush privileges; +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; +grant select on *.* to rpl_do_grant@localhost; +grant drop on test.* to rpl_do_grant@localhost; +show grants for rpl_do_grant@localhost; +Grants for rpl_do_grant@localhost +GRANT SELECT ON *.* TO 'rpl_do_grant'@'localhost' +GRANT DROP ON `test`.* TO 'rpl_do_grant'@'localhost' +set password for rpl_do_grant@localhost=password("does it work?"); +select password<>'' from mysql.user where user='rpl_do_grant'; +password<>'' +1 +delete from mysql.user where user='rpl_do_grant'; +delete from mysql.db where user='rpl_do_grant'; +flush privileges; +flush privileges; diff --git a/mysql-test/r/rpl_ignore_grant.result b/mysql-test/r/rpl_ignore_grant.result new file mode 100644 index 00000000000..6cd7d5b4c00 --- /dev/null +++ b/mysql-test/r/rpl_ignore_grant.result @@ -0,0 +1,37 @@ +slave stop; +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; +slave start; +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; +grant select on *.* to rpl_ignore_grant@localhost; +grant drop on test.* to rpl_ignore_grant@localhost; +show grants for rpl_ignore_grant@localhost; +Grants for rpl_ignore_grant@localhost +GRANT SELECT ON *.* TO 'rpl_ignore_grant'@'localhost' +GRANT DROP ON `test`.* TO 'rpl_ignore_grant'@'localhost' +show grants for rpl_ignore_grant@localhost; +There is no such grant defined for user 'rpl_ignore_grant' on host 'localhost' +select count(*) from mysql.user where user='rpl_ignore_grant'; +count(*) +0 +select count(*) from mysql.db where user='rpl_ignore_grant'; +count(*) +0 +grant select on *.* to rpl_ignore_grant@localhost; +set password for rpl_ignore_grant@localhost=password("does it work?"); +select password<>'' from mysql.user where user='rpl_ignore_grant'; +password<>'' +0 +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; diff --git a/mysql-test/t/rpl_do_grant.test b/mysql-test/t/rpl_do_grant.test new file mode 100644 index 00000000000..89ff1afb5c9 --- /dev/null +++ b/mysql-test/t/rpl_do_grant.test @@ -0,0 +1,46 @@ +# Test that GRANT and SET PASSWORD are replicated to the slave + +source include/master-slave.inc; + +# do not be influenced by other tests. +connection master; +delete from mysql.user where user='rpl_do_grant'; +delete from mysql.db where user='rpl_do_grant'; +flush privileges; +save_master_pos; +connection slave; +sync_with_master; +# if these DELETE did nothing on the master, we need to do them manually on the +# slave. +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; + +# test replication of GRANT +connection master; +grant select on *.* to rpl_do_grant@localhost; +grant drop on test.* to rpl_do_grant@localhost; +save_master_pos; +connection slave; +sync_with_master; +show grants for rpl_do_grant@localhost; + +# test replication of SET PASSWORD +connection master; +set password for rpl_do_grant@localhost=password("does it work?"); +save_master_pos; +connection slave; +sync_with_master; +select password<>'' from mysql.user where user='rpl_do_grant'; + +# clear what we have done, to not influence other tests. +connection master; +delete from mysql.user where user='rpl_do_grant'; +delete from mysql.db where user='rpl_do_grant'; +flush privileges; +save_master_pos; +connection slave; +sync_with_master; +# no need to delete manually, as the DELETEs must have done some real job on +# master (updated binlog) +flush privileges; diff --git a/mysql-test/t/rpl_ignore_grant-slave.opt b/mysql-test/t/rpl_ignore_grant-slave.opt new file mode 100644 index 00000000000..e931bfbd37e --- /dev/null +++ b/mysql-test/t/rpl_ignore_grant-slave.opt @@ -0,0 +1 @@ +--replicate-wild-ignore-table=mysql.% diff --git a/mysql-test/t/rpl_ignore_grant.test b/mysql-test/t/rpl_ignore_grant.test new file mode 100644 index 00000000000..2fd7f186b3e --- /dev/null +++ b/mysql-test/t/rpl_ignore_grant.test @@ -0,0 +1,57 @@ +# Test that GRANT is not replicated to the slave +# when --replicate-wild-ignore-table=mysql.% +# In BUG#980, this test would _randomly_ fail. + +source include/master-slave.inc; + +# do not be influenced by other tests. +connection master; +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; +save_master_pos; +connection slave; +sync_with_master; +# as these DELETE were not replicated, we need to do them manually on the +# slave. +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; + +# test non-replication of GRANT +connection master; +grant select on *.* to rpl_ignore_grant@localhost; +grant drop on test.* to rpl_ignore_grant@localhost; +show grants for rpl_ignore_grant@localhost; +save_master_pos; +connection slave; +sync_with_master; +--error 1141 #("no such grant for user") +show grants for rpl_ignore_grant@localhost; +# check it another way +select count(*) from mysql.user where user='rpl_ignore_grant'; +select count(*) from mysql.db where user='rpl_ignore_grant'; + +# test non-replication of SET PASSWORD +# first force creation of the user on slave (because as the user does not exist +# on slave, the SET PASSWORD may be replicated but silently do nothing; this is +# not what we want; we want it to be not-replicated). +grant select on *.* to rpl_ignore_grant@localhost; +connection master; +set password for rpl_ignore_grant@localhost=password("does it work?"); +save_master_pos; +connection slave; +sync_with_master; +select password<>'' from mysql.user where user='rpl_ignore_grant'; + +# clear what we have done, to not influence other tests. +connection master; +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; +save_master_pos; +connection slave; +sync_with_master; +delete from mysql.user where user='rpl_ignore_grant'; +delete from mysql.db where user='rpl_ignore_grant'; +flush privileges; diff --git a/sql/sql_acl.cc b/sql/sql_acl.cc index fd7ea5aac51..3a3de2abf10 100644 --- a/sql/sql_acl.cc +++ b/sql/sql_acl.cc @@ -1233,6 +1233,25 @@ static bool update_user_table(THD *thd, const char *host, const char *user, bzero((char*) &tables,sizeof(tables)); tables.alias=tables.real_name=(char*) "user"; tables.db=(char*) "mysql"; +#ifdef HAVE_REPLICATION + /* + GRANT and REVOKE are applied the slave in/exclusion rules as they are + some kind of updates to the mysql.% tables. + */ + if (thd->slave_thread && table_rules_on) + { + /* + The tables must be marked "updating" so that tables_ok() takes them into + account in tests. + */ + tables.updating=1; + /* Thanks to bzero, tables.next==0 */ + if (!tables_ok(0, &tables)) + DBUG_RETURN(0); + tables.updating=0; + } +#endif + if (!(table=open_ltable(thd,&tables,TL_WRITE))) DBUG_RETURN(1); /* purecov: deadcode */ table->field[0]->store(host,(uint) strlen(host));