###############################################################################
#                                                                             #
#  This script executes partial_revokes scenarios in following modes :        #
#  1. Normal        :   Script executes on single server                      #
#  2. Replication   :   Script executes in replication setup                  #
#                       on a master and a slave                               #
#                                                                             #
#   Arguments required:                                                       #
#   1. $TEST_MODE - [NORMAL | RPL]                                            #
#                                                                             #
###############################################################################

# If required parameters are not set then throw error and exit.
--let PARAM_PERL_QUIT=0
if ($TEST_MODE == '')
{
--let VARIABLE_NAME = TEST_MODE
--let PARAM_PERL_QUIT=1
}

--perl
    $variable_name = "$ENV{VARIABLE_NAME}";
    die "Error: partial_revokes_add_remove.inc: input variable $variable_name is missing!"
             if ($ENV{PARAM_PERL_QUIT} == 1);
EOF
CREATE DATABASE pr_db;
CREATE DATABASE normal_db;
CREATE TABLE pr_db.t1(c1 int, c2 int);
INSERT INTO pr_db.t1 values (1,2), (3,4);
CREATE TABLE normal_db.t1(c1 int, c2 int);
INSERT INTO normal_db.t1 values (1,2), (3,4);
--let $conn_name = foo_master
--let $reconn_name = foo_master_reconn
--let $bar_conn = bar_master
--echo -------------------------------------------------------------------------
--echo Tests related to users
--echo -------------------------------------------------------------------------
--echo #
--echo # 1. Grantor does not have restriction list but has global priv
--echo #
CREATE USER foo, bar;
GRANT INSERT,SELECT ON *.* TO foo WITH GRANT OPTION;

--connect($conn_name, localhost, foo,,,$MASTER_MYPORT)
--echo [connection $conn_name]
--echo # Must fail since no priv granted to bar yet.
--error ER_NONEXISTING_GRANT
REVOKE INSERT ON mysql.* FROM bar;
--echo # Create global insert priv with partial revoke for bar.
GRANT INSERT ON *.* TO bar;
REVOKE INSERT ON mysql.* FROM bar;
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--echo # Clear partial revoke from bar but global INSERT priv remains as it is
GRANT INSERT ON *.* TO bar;
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--echo # Create the partial revoke on mysql db again.
REVOKE INSERT ON mysql.* FROM bar;
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--echo # Remove partial revoke only
GRANT INSERT ON mysql.* TO bar;
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--echo # Grant DB level privilege only
GRANT INSERT ON mysql.* TO bar;
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
disconnect $conn_name;
DROP USER foo, bar;

--echo #
--echo # 2. Grantor has restriction list and grantee has global priv
--echo #
CREATE USER foo, bar;
GRANT INSERT, SELECT, UPDATE ON *.* TO foo WITH GRANT OPTION;
--echo # Restrict INSERT on mysql DB.
REVOKE INSERT ON mysql.* FROM foo;
SHOW GRANTS FOR foo;
--echo # Restrict UPDATE on mysql DB as well.
REVOKE UPDATE ON mysql.* FROM foo;
SHOW GRANTS FOR foo;
--echo # Must fail, DELETE privilege is not granted
--error ER_NONEXISTING_GRANT
REVOKE DELETE ON mysql.* FROM foo;
GRANT INSERT ON *.* TO bar;
--connect($conn_name, localhost, foo,,,$MASTER_MYPORT)
--echo [connection $conn_name]
--error ER_DBACCESS_DENIED_ERROR
GRANT INSERT ON mysql.* TO bar;
--error ER_DBACCESS_DENIED_ERROR
REVOKE INSERT ON mysql.* FROM bar;
--error ER_DB_ACCESS_DENIED
REVOKE INSERT ON *.* FROM bar;
--echo # Grantee will not get the restriction list from grantor because
--echo # former already has higher priv than grantor
GRANT INSERT ON *.* TO bar;
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
disconnect $conn_name;
DROP USER foo, bar;

--echo #
--echo # 3. Grantor has restriction list and grantee has DB level privileges
--echo #
CREATE USER foo, bar;
GRANT INSERT, UPDATE, SELECT ON *.* TO foo WITH GRANT OPTION;
--echo # Restrict INSERT and UPDATE on mysql DB from foo.
REVOKE INSERT,UPDATE ON mysql.* FROM foo;
SHOW GRANTS FOR foo;
--echo # Grant DB level INSERT priv on mysql DB to bar.
GRANT INSERT ON mysql.* TO bar;
SHOW GRANTS FOR bar;
--connect($conn_name, localhost, foo,,,$MASTER_MYPORT)
--echo [connection $conn_name]
--error ER_DBACCESS_DENIED_ERROR
REVOKE INSERT ON mysql.* FROM bar;
--error ER_DB_ACCESS_DENIED
REVOKE INSERT ON *.* FROM bar;
--error ER_DBACCESS_DENIED_ERROR
GRANT INSERT ON mysql.* TO bar;
--echo # There should not be any restriction list:
--echo #    INSERT on mysql DB because bar already has access to this DB
--echo #    UPDATE on mysql DB because global UPDATE priv is not being granted
GRANT INSERT ON *.* TO bar;
SHOW GRANTS FOR bar;
--connection default
--echo # Should be able to grant/revoke other DB level privileges without
--echo # affecting existing partial revokes.
REVOKE ALL ON *.* FROM bar;
--connection $conn_name
GRANT INSERT ON *.* TO bar;
GRANT INSERT ON `pr_db`.* TO bar;
SHOW GRANTS FOR bar;
--echo # Revoke the privilge. Partial revokes should remain intact
REVOKE INSERT ON `pr_db`.* FROM bar;
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
disconnect $conn_name;
DROP USER foo, bar;

--echo #
--echo # 4. Grantor and grantee both have restriction list
--echo #
--echo # 4.1 Restrictions are aggregated
CREATE USER foo, bar;
GRANT INSERT, SELECT, UPDATE ON *.* TO foo WITH GRANT OPTION;
--echo # Restrict INSERT, UPDATE on mysql DB from foo.
REVOKE INSERT, UPDATE ON mysql.* FROM foo;
SELECT user, user_attributes FROM mysql.user WHERE user LIKE 'foo';
GRANT DELETE, DROP, UPDATE, SELECT ON *.* TO bar;
--echo # Restrict UPDATE and DROP on mysql DB.
REVOKE UPDATE, DROP ON mysql.* FROM bar;
SHOW GRANTS FOR bar;
--connect($conn_name, localhost, foo,,,$MASTER_MYPORT)
--echo [connection $conn_name]
--echo # Restrictions from Grantor and Grantee must be aggregated
GRANT INSERT ON *.* TO bar;
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
--disconnect $conn_name
REVOKE ALL ON *.* FROM foo, bar;
--echo # 4.2 Restrictions are cleared
GRANT SELECT, CREATE, ALTER ON *.* TO foo WITH GRANT OPTION;
REVOKE SELECT ON mysql.* FROM foo;
GRANT SELECT, CREATE ON *.* TO bar;
REVOKE CREATE ON mysql.* FROM bar;
SHOW GRANTS FOR foo;
SHOW GRANTS FOR bar;
--connect($conn_name, localhost, foo,,,$MASTER_MYPORT)
--echo [connection $conn_name]
--echo # Aggregated restrictions turns out to be empty
GRANT SELECT, CREATE,ALTER ON *.* TO bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
SHOW GRANTS FOR bar;
disconnect $conn_name;
DROP USER foo, bar;
--echo #
--echo # 5. Grantor has restriction list and grantee does not have any priv
--echo #
CREATE USER foo, bar;
GRANT INSERT, SELECT ON *.* TO foo WITH GRANT OPTION;
--connect($conn_name, localhost, foo,,,$MASTER_MYPORT)
--echo [connection $conn_name]
--echo # Grantor should be able to add revoke on mysql DB on itself
REVOKE INSERT ON mysql.* FROM foo;
SHOW GRANTS FOR foo;
--connect($reconn_name, localhost, foo,,,$MASTER_MYPORT)
--echo [connection $reconn_name]
--echo # Restrictions must remain intact if grantor reconnects and try to
--echo # grant global privilege to self. In other words, it must be no-op.
GRANT INSERT ON *.* TO foo;
SHOW GRANTS FOR foo;
--echo # Grantee should get the restriction_list of grantor
GRANT INSERT, SELECT ON *.* TO bar;
SHOW GRANTS FOR bar;
--echo # Grantor should be able to add additional restrictions list
REVOKE INSERT,SELECT ON `pr_db`.* FROM bar;
SHOW GRANTS FOR bar;
--echo # Additional restrictions of Grantee should be removed.
GRANT INSERT, SELECT ON *.* TO bar;
SHOW GRANTS FOR bar;
--echo # Should remove, the  global privileges and restrictions both
REVOKE SELECT, INSERT ON *.* FROM bar;
SHOW GRANTS FOR bar;
--echo # Grantee should get the restriction_list of grantor again
GRANT INSERT, SELECT ON *.* TO bar;
SHOW GRANTS FOR bar;
--echo # Remove only global privilege from grantee
REVOKE SELECT ON *.* FROM bar;
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
disconnect $conn_name;
disconnect $reconn_name;
DROP USER foo, bar;

--echo #
--echo # 6. Revoke global privilege as well restriction list from grantee
--echo #    when grantor does not have restriction list
--echo #
CREATE USER foo, bar;
GRANT SELECT, INSERT ON *.* TO foo WITH GRANT OPTION;
--echo # User already have DB level priv
GRANT INSERT ON mysql.* TO bar;
--connect($conn_name, localhost, foo,,,$MASTER_MYPORT)
--echo [connection $conn_name]
--echo # Grant global INSERT privilege to bar
GRANT INSERT ON *.* TO bar;
--echo # Revoke INSERT on mysql DB from bar
REVOKE INSERT ON mysql.* FROM bar;
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--echo # Add partial revoke INSERT on mysql DB for bar.
REVOKE INSERT ON mysql.* FROM bar;
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--echo # Revoke Global privilege as well  as partial revoke.
REVOKE INSERT ON *.* FROM bar;
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
disconnect $conn_name;
--connection default
DROP USER foo,bar;

--echo #
--echo # 7. Granting a global privilege should not affect the restrictions
--echo #    of different privileges on other databases.
--echo #
CREATE USER foo;
CREATE DATABASE  secret;
CREATE DATABASE  meeting;
GRANT INSERT, SELECT, UPDATE ON *.* TO foo;
REVOKE SELECT,INSERT ON secret.* FROM foo;
REVOKE SELECT, UPDATE ON meeting.* FROM foo;
SHOW GRANTS FOR foo;
--echo # Only SELECT restrictions should have removed from
--echo # all databases in the restriction_list
GRANT SELECT ON *.* TO foo;
SHOW GRANTS FOR foo;
DROP USER foo;
DROP DATABASE secret;
DROP DATABASE meeting;

--echo #
--echo # 8. Granting a DB level privilege should not affect the restrictions
--echo #    of different privileges on other databases.
--echo #
CREATE USER foo;
CREATE DATABASE  secret;
CREATE DATABASE  meeting;
GRANT INSERT,DELETE, SELECT, UPDATE ON *.* TO foo;
GRANT SELECT,INSERT ON meeting.* TO foo;
GRANT DELETE,UPDATE ON secret.* TO foo;
REVOKE SELECT,INSERT ON secret.* FROM foo;
REVOKE DELETE, UPDATE ON meeting.* FROM foo;
--echo # Grant sub-set from the set of already granted privileges
GRANT SELECT ON meeting.* TO foo WITH GRANT OPTION;
--echo # The restrictions should not have modified.
SHOW GRANTS FOR foo;
--echo # Grant all privileges from set of already granted privileges
GRANT SELECT,INSERT ON meeting.* TO foo WITH GRANT OPTION;
--echo # The restrictions should not have modified.
SHOW GRANTS FOR foo;
--echo # Grant sub-set from the set of already granted privileges
GRANT UPDATE ON secret.* TO foo;
--echo # The restrictions should not have modified.
SHOW GRANTS FOR foo;
--echo # Grant all privileges from set of already granted privileges
GRANT DELETE,UPDATE ON secret.* TO foo;
--echo # The restrictions should not have modified.
SHOW GRANTS FOR foo;
--echo # Remove the partial revokes
GRANT SELECT,INSERT ON secret.* TO foo;
GRANT DELETE,UPDATE ON meeting.* TO foo;
SHOW GRANTS FOR foo;
DROP USER foo;
DROP DATABASE secret;
DROP DATABASE meeting;

--echo #
--echo # 9. Revoke all privileges from user(s)
--echo #
CREATE USER foo, bar, baz;
CREATE DATABASE secret_db;
--echo #
--echo # 9.1. Grantor has restriction list but grantee does not.
GRANT ALL ON *.* TO foo,baz;
GRANT ALL ON mysql.* TO foo,baz;
GRANT ALL ON mysql.* TO bar;
--echo # All privileges must be cleared from all three users
REVOKE ALL ON *.* FROM foo;
REVOKE ALL ON mysql.* FROM baz;
REVOKE ALL ON mysql.* FROM bar;
SHOW GRANTS FOR foo;
SHOW GRANTS FOR bar;
SHOW GRANTS FOR baz;
DROP USER baz;
--echo # Create partial_revokes for foo
GRANT ALL ON *.* TO foo WITH GRANT OPTION;
REVOKE SELECT ON mysql.* FROM foo;
--echo # GRANT ALL should remove the partial revokes created above
GRANT ALL ON *.* TO foo WITH GRANT OPTION;
SHOW GRANTS FOR foo;
--echo # create partial revokes again
REVOKE SELECT ON mysql.* FROM foo;
SHOW GRANTS FOR foo;
GRANT ALL ON mysql.* TO bar;
--connect($conn_name, localhost, foo,,,$MASTER_MYPORT)
--echo [connection $conn_name]
--error ER_DB_ACCESS_DENIED
REVOKE ALL ON *.* FROM bar;
--connection default
REVOKE ALL ON mysql.* FROM bar;
GRANT ALL ON *.* TO bar;
REVOKE SELECT ON mysql.* FROM bar;
--echo # grantor and grantee both have exact same privileges and partial revokes
SHOW GRANTS FOR foo;
SHOW GRANTS FOR bar;
--connection $conn_name
--echo # grantor should be able to remove the privileges & partial revokes both
REVOKE ALL ON *.* FROM bar;
--connection default
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
--disconnect $conn_name
REVOKE ALL ON *.* FROM foo,bar;
--echo #
--echo # 9.2. REVOKE ALL followed by GLOBAL grants should create restrictions
--connection default
GRANT ALL ON *.* TO foo WITH GRANT OPTION;
--echo # Following should create restrictions for mysql db
REVOKE ALL ON mysql.* FROM foo;
SHOW GRANTS FOR foo;
--connect($conn_name, localhost, foo,,,$MASTER_MYPORT)
--echo # restrictions must pass to bar as well
GRANT ALL ON *.* TO bar;
--connection default
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
--disconnect $conn_name
REVOKE ALL ON *.* FROM foo,bar;

--echo #
--echo # 9.3. Grantee has restriction list but grantor does not.
GRANT CREATE USER ON *.* TO foo WITH GRANT OPTION;
GRANT INSERT,SELECT ON *.* TO foo, bar;
REVOKE SELECT,INSERT ON mysql.* FROM bar;
REVOKE INSERT ON secret_db.* FROM bar;
SHOW GRANTS FOR bar;
--connect($conn_name, localhost, foo,,,$MASTER_MYPORT)
--echo [connection $conn_name]
REVOKE ALL ON *.* FROM bar;
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
--disconnect $conn_name
--echo #
--echo # 9.4. Grantor and grantee both have restriction_list
GRANT INSERT,SELECT ON *.* TO bar;
REVOKE SELECT ON mysql.* FROM bar;
REVOKE SELECT,INSERT ON secret_db.* FROM bar;
SHOW GRANTS FOR bar;
GRANT UPDATE ON *.* TO foo;
REVOKE UPDATE,SELECT ON secret_db.* FROM foo;
SHOW GRANTS FOR foo;
--connect($conn_name, localhost, foo,,,$MASTER_MYPORT)
--echo [connection $conn_name]
--echo # Should fail because foo cannot remove SELECT priv on bar
--error ER_DB_ACCESS_DENIED
REVOKE ALL ON *.* FROM bar;
--connection default
--disconnect $conn_name
GRANT SELECT ON `secret_db`.* TO foo;
SHOW GRANTS FOR foo;
--connect($conn_name, localhost, foo,,,$MASTER_MYPORT)
--echo [connection $conn_name]
--echo # Should work because restriction on foo is different from bar
REVOKE ALL ON *.* FROM bar;
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
--disconnect $conn_name
DROP USER  foo, bar;
DROP DATABASE secret_db;

--echo #
--echo # 10. Revoke a global privilege from grantee which is not present in the
--echo #     grantor's restriction_list
--echo #
CREATE USER foo, bar;
GRANT SELECT,INSERT ON *.* TO foo WITH GRANT OPTION;
REVOKE INSERT ON mysql.* FROM foo;
GRANT SELECT ON *.* TO bar;
SHOW GRANTS FOR foo;
--connect($conn_name, localhost, foo,,,$MASTER_MYPORT)
--echo [connection $conn_name]
--echo # Should work because restriction on foo is different from bar
REVOKE SELECT ON *.* FROM bar;
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
--disconnect $conn_name
DROP USER  foo, bar;

--echo #
--echo # 11. Partial revokes with anonymous user
--echo #
INSERT INTO pr_db.t1 values (1,2), (3,4);
INSERT INTO normal_db.t1 values (1,2), (3,4);
--echo #
--echo # 11.1 Grantor is anonymous user
--echo #
--let $USER_1 = ''@'%'
--let $USER_2 = ''@''
# We can't create ''@'%' unless we delete row from mysql.db
# Disable warning when running on binlog_format=stmt, to keep
# keep the result files same for all binlog format.
--disable_warnings
CREATE TEMPORARY TABLE mysql.db_copy AS SELECT * FROM mysql.db;
--enable_warnings
DELETE FROM mysql.db WHERE host='%';
FLUSH PRIVILEGES;
eval CREATE USER $USER_1, $USER_2;
# Restore mysql.db to its original state
eval GRANT SELECT ON *.* TO $USER_1 WITH GRANT OPTION;
eval REVOKE SELECT ON pr_db.* FROM $USER_1;
--let $conn_name = anonymous_con_1
--connect($conn_name,localhost,anon,,,$MASTER_MYPORT)
--echo [connection $conn_name]
SHOW GRANTS;
SELECT COUNT(*) FROM normal_db.t1;
--error ER_TABLEACCESS_DENIED_ERROR
SELECT COUNT(*) FROM pr_db.t1;
eval GRANT SELECT ON *.* TO $USER_2;
eval SHOW GRANTS FOR $USER_2;
--connection default
--disconnect $conn_name
eval DROP USER $USER_1,$USER_2;
--echo #
--echo # 11.2 Grantee is anonymous user
--echo #
--let $USER_1 = foo@localhost
--let $USER_2 = ''@'%'
eval CREATE USER $USER_1,$USER_2;
eval GRANT SELECT ON *.* TO $USER_1,$USER_2 WITH GRANT OPTION;
--let $conn_name = foo_master
--connect($conn_name,localhost,foo,,,$MASTER_MYPORT)
--echo [connection $conn_name]
--echo # Create partial revoke for anonymous user from normal user
eval REVOKE SELECT ON pr_db.* FROM $USER_2;
eval SHOW GRANTS FOR $USER_2;
--disconnect $conn_name
--echo # Anynmous user cannot access the restricted database
--let $conn_name = anonymous_con_1
--connect($conn_name,localhost,anon,,,$MASTER_MYPORT)
--echo [connection $conn_name]
SELECT COUNT(*) FROM normal_db.t1;
--error ER_TABLEACCESS_DENIED_ERROR
SELECT COUNT(*) FROM pr_db.t1;
--connection default
--disconnect $conn_name
eval DROP USER $USER_1,$USER_2;
# Restore mysql.db to its original state
DELETE FROM mysql.db;
INSERT INTO mysql.db SELECT * FROM mysql.db_copy;
FLUSH PRIVILEGES;
DROP TABLE mysql.db_copy;
--echo #
--echo # 12. Hybrid scenarios
--echo #
CREATE USER foo, bar;
CREATE DATABASE robo;
GRANT UPDATE, INSERT ON *.* TO bar;
REVOKE UPDATE, INSERT ON robo.* FROM bar;
SHOW GRANTS FOR bar;
--echo # 12.1. Remove the applicable partial revokes(update and insert) as
--echo #       well as grant applicable DB level privileges(select and delete)
GRANT INSERT, UPDATE, DELETE, SELECT ON robo.* TO bar;
SHOW GRANTS FOR bar;
--echo # 12.2. Add the applicable partial revokes(update and insert) as well
--echo #       as revoke applicable DB level privileges(select and delete)
REVOKE INSERT, UPDATE, DELETE, SELECT ON robo.* FROM bar;
SHOW GRANTS FOR bar;
--echo # 12.3 Grant global and DB level privilege then revoke the DB level
       #      privilege as well as create a partial revoke
GRANT SELECT, DROP ON *.* TO foo;
GRANT DROP ON robo.* TO foo;
SHOW GRANTS FOR foo;
REVOKE SELECT, DROP ON robo.* FROM foo;
SHOW GRANTS FOR foo;
# Cleanup
DROP USER foo,bar;
DROP DATABASE robo;
--echo #
--echo # 13. Misc scenarios
--echo #
--echo # 13.1 Revoking DB level privilege multiple times should not
--echo #      create/affect the restrictions
CREATE USER foo;
GRANT ALL ON mysql.* TO foo;
REVOKE SELECT ON mysql.* FROM foo;
REVOKE SELECT ON mysql.* FROM foo;
SHOW GRANTS FOR foo;
--echo # 13.2 Granting DB level privilege multiple times should not
--echo #      create/affect the restrictions
REVOKE ALL ON mysql.* FROM foo;
GRANT SELECT ON mysql.* TO foo;
GRANT SELECT ON mysql.* TO foo;
SHOW GRANTS FOR foo;
DROP USER foo;

--echo ------------Tests related to Users end here -----------------------------

--echo -------------------------------------------------------------------------
--echo Tests related to Roles
--echo -------------------------------------------------------------------------

--echo #
--echo # 1. Activate/Deactivate roles with partial revokes
--echo #
CREATE USER foo, bar;
CREATE ROLE insert_role, select_role;
GRANT INSERT ON *.* TO insert_role WITH GRANT OPTION;
REVOKE INSERT ON pr_db.* FROM insert_role;
GRANT SELECT ON *.* TO select_role WITH GRANT OPTION;
REVOKE SELECT ON pr_db.* FROM select_role;
GRANT ROLE_ADMIN ON *.* TO foo;
GRANT select_role TO foo;
GRANT insert_role TO foo;
SHOW GRANTS FOR foo;
--let $conn_name = foo_master
--connect($conn_name, localhost, foo,,,$MASTER_MYPORT)
--echo [connection $conn_name]
--echo # Must fail because foo does not have the SELECT privilege
--error ER_TABLEACCESS_DENIED_ERROR
SELECT COUNT(*) FROM mysql.user WHERE user = 'foo';
--echo # 1.1. Activate the select_role, now SELECT should work except on pr_db
SET ROLE select_role;
SHOW GRANTS;
SELECT COUNT(*) FROM normal_db.t1;
--error ER_TABLEACCESS_DENIED_ERROR
SELECT COUNT(*) FROM pr_db.t1;
--echo # Grant roles to another user 'bar'
GRANT select_role TO bar;
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--echo # 1.2. Activate the insert_role and deactivate the select_role
SET ROLE ALL EXCEPT select_role;
SHOW GRANTS;
--echo # select must fail but insert should work
--error ER_TABLEACCESS_DENIED_ERROR
SELECT COUNT(*) FROM normal_db.t1;
INSERT INTO normal_db.t1 values (5,6);
--echo # Grant roles to another user 'bar'
GRANT insert_role TO bar;
--connection default
SHOW GRANTS FOR bar;
--connection $conn_name
--source ./partial_revokes_rpl_helper.inc
--echo # 1.3. Deactivate the select_role activated before
SET ROLE NONE;
SHOW GRANTS;
--error ER_TABLEACCESS_DENIED_ERROR
SELECT COUNT(*) FROM normal_db.t1;
--error ER_TABLEACCESS_DENIED_ERROR
INSERT INTO normal_db.t1 values (5,6);
--echo # 1.4. Activate all roles
SET ROLE ALL;
SHOW GRANTS;
INSERT INTO normal_db.t1 values (7,8);
SELECT COUNT(*) FROM normal_db.t1;
--error ER_TABLEACCESS_DENIED_ERROR
SELECT COUNT(*) FROM pr_db.t1;
--error ER_TABLEACCESS_DENIED_ERROR
INSERT INTO pr_db.t1 values (7,8);
GRANT insert_role, select_role TO bar;
--connection default
SHOW GRANTS FOR bar;
--connection $conn_name
--source ./partial_revokes_rpl_helper.inc
--echo # Deactivate the select_role activated before
SET ROLE NONE;
--connection default
--echo #
--echo # 2. Default roles with partial revokes
--echo #
CREATE USER baz;
GRANT select_role to baz;
SHOW GRANTS FOR foo;
SHOW GRANTS FOR bar;
SHOW GRANTS FOR baz;
ALTER USER foo DEFAULT ROLE ALL;
SET DEFAULT ROLE select_role TO baz;
--connection $conn_name
--echo [connection $conn_name]
SET ROLE DEFAULT;
SHOW GRANTS;
INSERT INTO normal_db.t1 values (9,10);
SELECT COUNT(*) FROM normal_db.t1;
--error ER_TABLEACCESS_DENIED_ERROR
SELECT COUNT(*) FROM pr_db.t1;
--error ER_TABLEACCESS_DENIED_ERROR
INSERT INTO pr_db.t1 values (9,10);
GRANT insert_role, select_role TO bar;
--connection default
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--let $conn_name = baz_master
--connect($conn_name, localhost, baz,,,$MASTER_MYPORT)
--echo [connection $conn_name]
SET ROLE DEFAULT;
SHOW GRANTS;
SELECT COUNT(*) FROM normal_db.t1;
--error ER_TABLEACCESS_DENIED_ERROR
SELECT COUNT(*) FROM pr_db.t1;
--connection default
--disconnect $conn_name
DROP USER baz;
--echo # Reset the default roles granted to foo earlier
--let $conn_name = foo_master
--connection $conn_name
--echo [connection $conn_name]
SET ROLE NONE;
--connection default
SET DEFAULT ROLE NONE TO foo;
--echo #
--echo # 3. Mandatory roles with partial revokes
--echo #
CREATE ROLE delete_role;
GRANT DELETE ON *.* TO delete_role;
REVOKE DELETE ON pr_db.* FROM delete_role;
SET GLOBAL mandatory_roles='delete_role';
--connection $conn_name
--echo [connection $conn_name]
SET ROLE delete_role;
SHOW GRANTS;
DELETE FROM normal_db.t1;
--error ER_TABLEACCESS_DENIED_ERROR
DELETE FROM pr_db.t1;
--connection default
SET GLOBAL mandatory_roles='';
DROP ROLE delete_role;
--disconnect $conn_name
DROP USER foo, bar;
DROP ROLE insert_role, select_role;

--echo #
--echo # 4. Aggregation should not reduce privileges
--echo #
--echo [connection default]
CREATE USER bar;
CREATE ROLE r1;
GRANT SELECT ON *.* TO r1, bar;
REVOKE SELECT ON mysql.* FROM r1;
GRANT INSERT ON *.* TO r1;
GRANT r1 TO bar;
SHOW GRANTS FOR bar;
SHOW GRANTS FOR bar USING 'r1';

--connect($bar_conn, localhost, bar,,,$MASTER_MYPORT)
--echo [connection $bar_conn]
SET ROLE ALL;
SELECT user FROM mysql.user WHERE user LIKE 'bar';
SHOW GRANTS;
--connection default
--echo [connection default]
REVOKE INSERT ON *.* FROM r1;
GRANT SELECT ON *.* TO r1, bar;
REVOKE SELECT ON mysql.* FROM bar;
SHOW GRANTS FOR bar;
SHOW GRANTS FOR bar USING 'r1';

--connection $bar_conn
--echo [connection $bar_conn]
SET ROLE ALL;
SELECT user FROM mysql.user WHERE user LIKE 'bar';

--connection default
--echo [connection default]
--disconnect $bar_conn
DROP ROLE r1;
DROP USER bar;

--echo #
--echo # 5. Restriction list of roles should apply to grantee
--echo #
--echo [connection default]
CREATE USER foo, bar;
CREATE ROLE r1;
GRANT SELECT ON *.* TO r1 WITH GRANT OPTION;
REVOKE SELECT ON mysql.* FROM r1;
GRANT r1 TO foo;

--connect($conn_name, localhost, foo,,,$MASTER_MYPORT)
--echo [connection $conn_name]
SET ROLE ALL;
SHOW GRANTS;
GRANT SELECT ON *.* TO bar;

--connection default
--echo [connection default]
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
--disconnect $conn_name
DROP ROLE r1;
DROP USER foo, bar;

--echo #
--echo # 6. Roles have restrictions but user has global privilege
--echo #
CREATE USER bar;
CREATE ROLE r1;
GRANT SELECT ON *.* TO r1, bar;
REVOKE SELECT ON mysql.* FROM r1;
GRANT r1 TO bar;
--let $conn_name = bar_master
--connect($conn_name, localhost, bar,,,$MASTER_MYPORT)
--echo [connection $conn_name]
SET ROLE ALL;
--echo # Restrictions of roles should not apply since user has higher privilege
SHOW GRANTS;
--echo # User's actual privileges ( and restrictions) must be visible
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
--disconnect $conn_name
DROP USER bar;
DROP ROLE r1;

--echo #
--echo # 7. Roles have global privilege but user has restrictions
--echo #
CREATE USER bar;
CREATE ROLE r1;
GRANT SELECT ON *.* TO r1, bar;
REVOKE SELECT ON mysql.* FROM bar;
GRANT r1 TO bar;
--let $conn_name = bar_master
--connect($conn_name, localhost, bar,,,$MASTER_MYPORT)
--echo [connection $conn_name]
SET ROLE ALL;
--echo # User's restrictions should be removed through grantor(role).
SHOW GRANTS;
--echo # User's actual privileges ( and restrictions) must be visible
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
--disconnect $conn_name
DROP USER bar;
DROP ROLE r1;

--echo #
--echo # 8. Roles negating each other's restrictions
--echo #
--echo # 8.1 Both roles have partial revokes
CREATE ROLE r1, r2;
CREATE USER bar;
GRANT SELECT,INSERT ON *.* TO r1, r2;
REVOKE SELECT ON mysql.* FROM r1;
REVOKE INSERT ON mysql.* FROM r2;
--echo # Grant privileges and roles to user
GRANT DROP ON *.* TO bar;
GRANT UPDATE ON mysql.* TO bar;
GRANT r1, r2 TO bar;
--echo # Roles privileges and restrictions should apply to user
SHOW GRANTS FOR bar USING r1;
SHOW GRANTS FOR bar USING r2;
--echo # Roles global privileges should negate each others restrictions
SHOW GRANTS FOR bar USING r1, r2;
--let $conn_name = bar_master
--connect($conn_name, localhost, bar,,,$MASTER_MYPORT)
--echo [connection $conn_name]
SET ROLE r1, r2;
SHOW GRANTS;
--source ./partial_revokes_rpl_helper.inc
--connection default
--disconnect $conn_name
DROP USER bar;
DROP ROLE r1, r2;
--echo # 8.2 One role has partial revoke and another has DB level grant
CREATE USER bar;
CREATE ROLE r1, r2;
GRANT r1, r2 TO bar;
GRANT SELECT ON *.* TO r1;
REVOKE SELECT ON mysql.* FROM r1;
GRANT SELECT ON mysql.* TO r2;
SHOW GRANTS FOR bar USING r1;
SHOW GRANTS FOR bar USING r2;
--echo # DB level privilege and partial revoke negate each other
SHOW GRANTS FOR bar USING r1, r2;
--let $conn_name = bar_master
--connect($conn_name, localhost, bar,,,$MASTER_MYPORT)
--echo [connection $conn_name]
SET ROLE r1, r2;
SHOW GRANTS;
SET ROLE r1;
SHOW GRANTS;
SET ROLE r2;
SHOW GRANTS;
SET ROLE r2, r1;
SHOW GRANTS;
--source ./partial_revokes_rpl_helper.inc
--connection default
--disconnect $conn_name
DROP USER bar;
DROP ROLE r1, r2;
--echo # 8.3 One role has partial revoke & grants and another has DB grants
CREATE USER bar;
CREATE ROLE r1, r2;
GRANT r1, r2 TO bar;
GRANT SELECT, DROP ON *.* TO r1;
REVOKE SELECT ON mysql.* FROM r1;
GRANT UPDATE ON mysql.* TO r1;
GRANT SELECT, INSERT ON mysql.* TO r2;
SHOW GRANTS FOR bar USING r1;
SHOW GRANTS FOR bar USING r2;
--echo # DB level privilege and partial revoke negate each other
SHOW GRANTS FOR bar USING r1, r2;
--let $conn_name = bar_master
--connect($conn_name, localhost, bar,,,$MASTER_MYPORT)
--echo [connection $conn_name]
SET ROLE r1, r2;
SHOW GRANTS;
--source ./partial_revokes_rpl_helper.inc
--connection default
--disconnect $conn_name
DROP USER bar;
DROP ROLE r1,r2;

--echo #
--echo # 9. SET ROLE removes the restrictions from the user. Now, Global
--echo #    grant/revoke should not carry restrictions to grantee
--echo #
CREATE USER foo, bar;
CREATE ROLE r1;

GRANT SELECT, INSERT ON *.* TO bar WITH GRANT OPTION;
REVOKE INSERT ON mysql.* FROM bar;
GRANT INSERT ON *.* TO r1;
GRANT r1 TO bar;
--let $conn_name = bar_master
--connect($conn_name, localhost, bar,,,$MASTER_MYPORT)
--echo [connection $conn_name]
--echo # User should not have restriction for now
SET ROLE ALL;
SHOW GRANTS;
--echo # Grantee should not carry the actual restrictions of grantor
GRANT INSERT ON *.* TO foo;
SHOW GRANTS FOR foo;
--echo # Grantor should be able to remove the global privileges from grantee now
REVOKE INSERT ON *.* FROM foo;
SHOW GRANTS FOR foo;
--echo # Grantor should be able to grant global privilege to self
GRANT INSERT ON *.* TO bar;
SHOW GRANTS;
--connection default
--echo [connection default]
--echo # Since, user granted himself global privilege therefore it's
--echo # restrictions has gone permanently now.
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
--disconnect $conn_name
DROP USER foo, bar;
DROP ROLE r1;

--echo #
--echo # 10. SET ROLE removes the restrictions from the user. Now, DB level
--echo #     grant/revoke should work as intended.
--echo #
CREATE USER foo, bar;
CREATE ROLE r1;

GRANT SELECT, INSERT ON *.* TO bar WITH GRANT OPTION;
REVOKE INSERT ON mysql.* FROM bar;
GRANT INSERT ON *.* TO r1;
GRANT r1 TO bar;
--let $conn_name = bar_master
--connect($conn_name, localhost, bar,,,$MASTER_MYPORT)
--echo [connection $conn_name]
--echo # User should not have restriction for now
SET ROLE ALL;
SHOW GRANTS;
--echo # Grantor should be able to grant DB level privilege to grantee
GRANT INSERT ON mysql.* TO foo;
SHOW GRANTS FOR foo;
--echo # Grantor should be able to revoke DB Level priviulege from grantee
REVOKE INSERT ON mysql.* FROM foo;
SHOW GRANTS FOR foo;
--echo # Should be able to grant DB level privilege to self
GRANT INSERT ON mysql.* TO bar;
SHOW GRANTS;
--connection default
--echo [connection default]
--echo # Since, user granted himself DB level privilege therefore it's
--echo # restrictions has gone permanently now.
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
--disconnect $conn_name
DROP USER foo, bar;
DROP ROLE r1;
--echo #
--echo # 11. SET ROLE removes the restrictions from the user. Now, DB level
--echo #     grant/revoke ALL should work as intended.
--echo #
CREATE USER foo, bar;
CREATE ROLE r1;
GRANT SELECT, INSERT ON *.* TO bar WITH GRANT OPTION;
GRANT ALL ON mysql.* TO bar;
REVOKE INSERT ON mysql.* FROM bar;
REVOKE INSERT ON mysql.* FROM bar;
GRANT INSERT ON *.* TO r1;
GRANT r1 TO bar;
--let $conn_name = bar_master
--connect($conn_name, localhost, bar,,,$MASTER_MYPORT)
--echo [connection $conn_name]
--echo # User should not have restriction for now
SET ROLE ALL;
SHOW GRANTS;
--echo # Grantor should be able to grant ALL DB level privilege to grantee
GRANT ALL ON mysql.* TO foo;
SHOW GRANTS FOR foo;
--echo # Grantor should be able to revoke ALL DB Level privilege from grantee
REVOKE ALL ON mysql.* FROM foo;
SHOW GRANTS FOR foo;
--echo # Should be able to grant ALL DB level privileges to self
GRANT ALL ON mysql.* TO bar;
SHOW GRANTS;
--connection default
--echo [connection default]
--echo # Since, user granted himself all DB level privileges therefore it's
--echo # restrictions has gone permanently now.
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
--disconnect $conn_name
DROP USER foo, bar;
DROP ROLE r1;
--echo #
--echo # 12. SET ROLE removes the restrictions from the user. Now, global
--echo #     grant/revoke ALL should work as intended.
--echo #
CREATE USER foo, bar;
CREATE ROLE r1;
GRANT ALL ON *.* TO bar WITH GRANT OPTION;
REVOKE INSERT ON mysql.* FROM bar;
GRANT INSERT ON *.* TO r1;
GRANT r1 TO bar;
--let $conn_name = bar_master
--connect($conn_name, localhost, bar,,,$MASTER_MYPORT)
--echo [connection $conn_name]
--echo # User should not have restriction for now
SET ROLE ALL;
SHOW GRANTS;
--echo # Grantor should be able to grant ALL global level privilege to grantee
GRANT ALL ON *.* TO foo;
SHOW GRANTS FOR foo;
--echo # Grantor should be able to revoke ALL global level privilege from
--echo # grantee
REVOKE ALL ON *.* FROM foo;
SHOW GRANTS FOR foo;
--echo # Should be able to grant ALL DB level privileges to self
GRANT ALL ON *.* TO bar;
SHOW GRANTS;
--connection default
--echo [connection default]
--echo # Since, user granted himself all DB level privileges therefore it's
--echo # restrictions has gone permanently now.
SHOW GRANTS FOR bar;
--source ./partial_revokes_rpl_helper.inc
--connection default
--disconnect $conn_name
DROP USER foo, bar;
DROP ROLE r1;
--echo ---------------------Tests related to roles end here---------------------

--echo -------------------------------------------------------------------------
--echo Invalid restrictions and privilege combinations
--echo -------------------------------------------------------------------------
CREATE USER foo, bar;
--echo #
--echo # 1. Add INSERT partial revoke on mysql DB for user bar
--echo #
GRANT SELECT, INSERT ON *.* TO bar;
REVOKE SELECT, INSERT ON mysql.* FROM bar;
SHOW GRANTS FOR bar;
INSERT INTO mysql.db(user,host, db, Insert_priv) VALUES('bar', '%', 'mysql', 'Y');
FLUSH PRIVILEGES;
SHOW GRANTS FOR bar;
--error ER_PARTIAL_REVOKE_AND_DB_GRANT_BOTH_EXISTS
GRANT INSERT ON *.* TO bar;
--error ER_PARTIAL_REVOKE_AND_DB_GRANT_BOTH_EXISTS
REVOKE INSERT ON *.* FROM bar;
--error ER_PARTIAL_REVOKE_AND_DB_GRANT_BOTH_EXISTS
GRANT INSERT ON mysql.* TO bar;
--error ER_PARTIAL_REVOKE_AND_DB_GRANT_BOTH_EXISTS
REVOKE INSERT ON mysql.* FROM bar;
--echo # We should not even able to grant/revoke fresh privileges.
--error ER_PARTIAL_REVOKE_AND_DB_GRANT_BOTH_EXISTS
GRANT UPDATE ON mysql.* TO bar;
--error ER_PARTIAL_REVOKE_AND_DB_GRANT_BOTH_EXISTS
REVOKE UPDATE ON mysql.* FROM bar;
--error ER_PARTIAL_REVOKE_AND_DB_GRANT_BOTH_EXISTS
GRANT UPDATE ON *.* TO bar;
--error ER_PARTIAL_REVOKE_AND_DB_GRANT_BOTH_EXISTS
REVOKE UPDATE ON *.* FROM bar;
--connect(conn_bar, localhost, bar,,,$MASTER_MYPORT)
# Should work
SELECT CURRENT_USER();
SELECT COUNT(*) FROM pr_db.t1;
--connection default
disconnect conn_bar;
DROP USER foo,bar;

--echo #
--echo # 2. Add privilege other than DB_ACLs in user attributes column.
--echo #
CREATE USER u1;
CREATE DATABASE db1;
GRANT SELECT, INSERT ON *.* TO u1;
REVOKE SELECT, INSERT ON db1.* FROM u1;
UPDATE mysql.user SET user_attributes='{"Restrictions": [{"Database": "db1", "Privileges": ["SELECT", "INSERT", "SUPER", "DELETE"]}]}' WHERE user = 'u1';
# We let our server restart attempts write to the file $server_log.
let server_log= $MYSQLTEST_VARDIR/log/mysqld.1.err;
let SEARCH_FILE= $server_log;

--echo # Search for : ignored restrictions for privilege(s) 'SUPER' for database 'db1' as these are not valid database privileges
let SEARCH_PATTERN= ignored restrictions for privilege(s) 'SUPER' for database 'db1' as these are not valid database privileges;
--source include/search_pattern.inc
--echo # Search completed.

--echo # Search for : ignored restrictions for privilege(s) 'DELETE' for database 'db1' as corresponding global privilege(s) are not granted
let SEARCH_PATTERN= ignored restrictions for privilege(s) 'DELETE' for database 'db1' as corresponding global privilege(s) are not granted;
--source include/search_pattern.inc
--echo # Search completed.

DROP DATABASE db1;
DROP USER u1;
--echo -Tests related to invalid restrictions & privilege combinations end here-
--echo
--echo -------------------------------------------------------------------------
--echo Partial revokes do not treat wildcard grants specially.
--echo -------------------------------------------------------------------------
CREATE USER foo;
CREATE DATABASE `db_1`;
CREATE DATABASE `db%1`;
GRANT SELECT ON *.* TO foo;

--echo # Create restriction - We dont use '\' to escape '_' or '%'
REVOKE SELECT ON `db_1`.* FROM foo;
REVOKE SELECT ON `db%1`.* FROM foo;

--echo # Should show 2 restrictions
SHOW GRANTS FOR foo;

--echo # Should not remove restrictions on db_1 or db%1,
--echo # instead both grants should be added on db(s) as it is.
GRANT SELECT ON `db\_1`.* TO foo;
GRANT SELECT ON `db\%1`.* TO foo;
SHOW GRANTS FOR foo;

--echo # Should remove two grants added above
REVOKE SELECT ON `db\_1`.* FROM foo;
REVOKE SELECT ON `db\%1`.* FROM foo;

--echo # Should show 2 restrictions
SHOW GRANTS FOR foo;

# Cleanup
REVOKE SELECT ON *.* FROM foo;
DROP USER foo;
DROP DATABASE `db_1`;
DROP DATABASE `db%1`;
--echo -------------------------------------------------------------------------
--echo Test related to wildcard grants end here.
--echo -------------------------------------------------------------------------

#
# Clean up
#
DROP DATABASE pr_db;
DROP DATABASE normal_db;
call mtr.add_suppression(".*Nothing to revoke. Global privilege.*");
