SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, rolpassword, rolvaliduntil FROM pg_authid WHERE rolname LIKE 'create\_%' ORDER BY rolname; rolname | rolsuper | rolinherit | rolcreaterole | rolcreatedb | rolcanlogin | rolreplication | rolbypassrls | rolconnlimit | rolpassword | rolvaliduntil --------------------------------------------------------------------- (0 rows) SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE 'create\_%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- (0 rows) \c - - - :worker_1_port SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, rolpassword, rolvaliduntil FROM pg_authid WHERE rolname LIKE 'create\_%' ORDER BY rolname; rolname | rolsuper | rolinherit | rolcreaterole | rolcreatedb | rolcanlogin | rolreplication | rolbypassrls | rolconnlimit | rolpassword | rolvaliduntil --------------------------------------------------------------------- (0 rows) SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE 'create\_%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- (0 rows) \c - - - :master_port CREATE ROLE create_role; CREATE ROLE create_role_2; CREATE USER create_user; CREATE USER create_user_2; CREATE GROUP create_group; CREATE GROUP create_group_2; -- show that create role fails if sysid option is given as non-int CREATE ROLE create_role_sysid SYSID "123"; ERROR: syntax error at or near ""123"" -- show that create role accepts sysid option as int CREATE ROLE create_role_sysid SYSID 123; NOTICE: SYSID can no longer be specified SELECT master_remove_node('localhost', :worker_2_port); master_remove_node --------------------------------------------------------------------- (1 row) CREATE ROLE create_role_with_everything SUPERUSER CREATEDB CREATEROLE INHERIT LOGIN REPLICATION BYPASSRLS CONNECTION LIMIT 105 PASSWORD 'strong_password123^' VALID UNTIL '2045-05-05 00:00:00.00+00' IN ROLE create_role, create_group ROLE create_user, create_group_2 ADMIN create_role_2, create_user_2; CREATE ROLE create_role_with_nothing NOSUPERUSER NOCREATEDB NOCREATEROLE NOINHERIT NOLOGIN NOREPLICATION NOBYPASSRLS CONNECTION LIMIT 3 PASSWORD 'weakpassword' VALID UNTIL '2015-05-05 00:00:00.00+00'; -- show that creating role from worker node is allowed \c - - - :worker_1_port CREATE ROLE role_on_worker; DROP ROLE role_on_worker; \c - - - :master_port -- edge case role names CREATE ROLE "create_role'edge"; CREATE ROLE "create_role""edge"; -- test grant role GRANT create_group TO create_role; GRANT create_group TO create_role_2 WITH ADMIN OPTION; SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, (rolpassword != '') as pass_not_empty, rolvaliduntil FROM pg_authid WHERE rolname LIKE 'create\_%' ORDER BY rolname; rolname | rolsuper | rolinherit | rolcreaterole | rolcreatedb | rolcanlogin | rolreplication | rolbypassrls | rolconnlimit | pass_not_empty | rolvaliduntil --------------------------------------------------------------------- create_group | f | t | f | f | f | f | f | -1 | | create_group_2 | f | t | f | f | f | f | f | -1 | | create_role | f | t | f | f | f | f | f | -1 | | create_role"edge | f | t | f | f | f | f | f | -1 | | create_role'edge | f | t | f | f | f | f | f | -1 | | create_role_2 | f | t | f | f | f | f | f | -1 | | create_role_sysid | f | t | f | f | f | f | f | -1 | | create_role_with_everything | t | t | t | t | t | t | t | 105 | t | Thu May 04 17:00:00 2045 PDT create_role_with_nothing | f | f | f | f | f | f | f | 3 | t | Mon May 04 17:00:00 2015 PDT create_user | f | t | f | f | t | f | f | -1 | | create_user_2 | f | t | f | f | t | f | f | -1 | | (11 rows) SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE 'create\_%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- create_group | create_role | postgres | f create_group | create_role_2 | postgres | t create_group | create_role_with_everything | postgres | f create_role | create_role_with_everything | postgres | f create_role_with_everything | create_group_2 | postgres | f create_role_with_everything | create_role_2 | postgres | t create_role_with_everything | create_user | postgres | f create_role_with_everything | create_user_2 | postgres | t (8 rows) \c - - - :worker_1_port SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, (rolpassword != '') as pass_not_empty, rolvaliduntil FROM pg_authid WHERE rolname LIKE 'create\_%' ORDER BY rolname; rolname | rolsuper | rolinherit | rolcreaterole | rolcreatedb | rolcanlogin | rolreplication | rolbypassrls | rolconnlimit | pass_not_empty | rolvaliduntil --------------------------------------------------------------------- create_group | f | t | f | f | f | f | f | -1 | | create_group_2 | f | t | f | f | f | f | f | -1 | | create_role | f | t | f | f | f | f | f | -1 | | create_role"edge | f | t | f | f | f | f | f | -1 | | create_role'edge | f | t | f | f | f | f | f | -1 | | create_role_2 | f | t | f | f | f | f | f | -1 | | create_role_sysid | f | t | f | f | f | f | f | -1 | | create_role_with_everything | t | t | t | t | t | t | t | 105 | t | Thu May 04 17:00:00 2045 PDT create_role_with_nothing | f | f | f | f | f | f | f | 3 | t | Mon May 04 17:00:00 2015 PDT create_user | f | t | f | f | t | f | f | -1 | | create_user_2 | f | t | f | f | t | f | f | -1 | | (11 rows) SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE 'create\_%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- create_group | create_role | postgres | f create_group | create_role_2 | postgres | t create_group | create_role_with_everything | postgres | f create_role | create_role_with_everything | postgres | f create_role_with_everything | create_group_2 | postgres | f create_role_with_everything | create_role_2 | postgres | t create_role_with_everything | create_user | postgres | f create_role_with_everything | create_user_2 | postgres | t (8 rows) \c - - - :master_port SELECT 1 FROM master_add_node('localhost', :worker_2_port); ?column? --------------------------------------------------------------------- 1 (1 row) \c - - - :worker_2_port SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, (rolpassword != '') as pass_not_empty, rolvaliduntil FROM pg_authid WHERE rolname LIKE 'create\_%' ORDER BY rolname; rolname | rolsuper | rolinherit | rolcreaterole | rolcreatedb | rolcanlogin | rolreplication | rolbypassrls | rolconnlimit | pass_not_empty | rolvaliduntil --------------------------------------------------------------------- create_group | f | t | f | f | f | f | f | -1 | | infinity create_group_2 | f | t | f | f | f | f | f | -1 | | infinity create_role | f | t | f | f | f | f | f | -1 | | infinity create_role"edge | f | t | f | f | f | f | f | -1 | | infinity create_role'edge | f | t | f | f | f | f | f | -1 | | infinity create_role_2 | f | t | f | f | f | f | f | -1 | | infinity create_role_sysid | f | t | f | f | f | f | f | -1 | | infinity create_role_with_everything | t | t | t | t | t | t | t | 105 | t | Thu May 04 17:00:00 2045 PDT create_role_with_nothing | f | f | f | f | f | f | f | 3 | t | Mon May 04 17:00:00 2015 PDT create_user | f | t | f | f | t | f | f | -1 | | infinity create_user_2 | f | t | f | f | t | f | f | -1 | | infinity (11 rows) SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE 'create\_%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- create_group | create_role | postgres | f create_group | create_role_2 | postgres | t create_group | create_role_with_everything | postgres | f create_role | create_role_with_everything | postgres | f create_role_with_everything | create_group_2 | postgres | f create_role_with_everything | create_role_2 | postgres | t create_role_with_everything | create_user | postgres | f create_role_with_everything | create_user_2 | postgres | t (8 rows) \c - - - :master_port DROP ROLE create_role_with_everything; REVOKE create_group FROM create_role; REVOKE ADMIN OPTION FOR create_group FROM create_role_2; \c - - - :master_port SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, (rolpassword != '') as pass_not_empty, rolvaliduntil FROM pg_authid WHERE rolname LIKE 'create\_%' ORDER BY rolname; rolname | rolsuper | rolinherit | rolcreaterole | rolcreatedb | rolcanlogin | rolreplication | rolbypassrls | rolconnlimit | pass_not_empty | rolvaliduntil --------------------------------------------------------------------- create_group | f | t | f | f | f | f | f | -1 | | create_group_2 | f | t | f | f | f | f | f | -1 | | create_role | f | t | f | f | f | f | f | -1 | | create_role"edge | f | t | f | f | f | f | f | -1 | | create_role'edge | f | t | f | f | f | f | f | -1 | | create_role_2 | f | t | f | f | f | f | f | -1 | | create_role_sysid | f | t | f | f | f | f | f | -1 | | create_role_with_nothing | f | f | f | f | f | f | f | 3 | t | Mon May 04 17:00:00 2015 PDT create_user | f | t | f | f | t | f | f | -1 | | create_user_2 | f | t | f | f | t | f | f | -1 | | (10 rows) SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE 'create\_%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- create_group | create_role_2 | postgres | f (1 row) \c - - - :worker_1_port SELECT rolname, rolsuper, rolinherit, rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, (rolpassword != '') as pass_not_empty, rolvaliduntil FROM pg_authid WHERE rolname LIKE 'create\_%' ORDER BY rolname; rolname | rolsuper | rolinherit | rolcreaterole | rolcreatedb | rolcanlogin | rolreplication | rolbypassrls | rolconnlimit | pass_not_empty | rolvaliduntil --------------------------------------------------------------------- create_group | f | t | f | f | f | f | f | -1 | | create_group_2 | f | t | f | f | f | f | f | -1 | | create_role | f | t | f | f | f | f | f | -1 | | create_role"edge | f | t | f | f | f | f | f | -1 | | create_role'edge | f | t | f | f | f | f | f | -1 | | create_role_2 | f | t | f | f | f | f | f | -1 | | create_role_sysid | f | t | f | f | f | f | f | -1 | | create_role_with_nothing | f | f | f | f | f | f | f | 3 | t | Mon May 04 17:00:00 2015 PDT create_user | f | t | f | f | t | f | f | -1 | | create_user_2 | f | t | f | f | t | f | f | -1 | | (10 rows) SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE 'create\_%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- create_group | create_role_2 | postgres | f (1 row) \c - - - :master_port create role test_admin_role; -- test grants with distributed and non-distributed roles SELECT master_remove_node('localhost', :worker_2_port); master_remove_node --------------------------------------------------------------------- (1 row) CREATE ROLE dist_role_1 SUPERUSER; CREATE ROLE dist_role_2; CREATE ROLE dist_role_3; CREATE ROLE dist_role_4; SET citus.enable_create_role_propagation TO OFF; CREATE ROLE non_dist_role_1 SUPERUSER; NOTICE: not propagating CREATE ROLE/USER commands to other nodes HINT: Connect to other nodes directly to manually create all necessary users and roles. CREATE ROLE non_dist_role_2; NOTICE: not propagating CREATE ROLE/USER commands to other nodes HINT: Connect to other nodes directly to manually create all necessary users and roles. CREATE ROLE non_dist_role_3; NOTICE: not propagating CREATE ROLE/USER commands to other nodes HINT: Connect to other nodes directly to manually create all necessary users and roles. CREATE ROLE non_dist_role_4; NOTICE: not propagating CREATE ROLE/USER commands to other nodes HINT: Connect to other nodes directly to manually create all necessary users and roles. SET citus.enable_create_role_propagation TO ON; grant dist_role_3,dist_role_1 to test_admin_role with admin option; SET ROLE dist_role_1; GRANT non_dist_role_1 TO non_dist_role_2; SET citus.enable_create_role_propagation TO OFF; grant dist_role_1 to non_dist_role_1 with admin option; SET ROLE non_dist_role_1; GRANT dist_role_1 TO dist_role_2 granted by non_dist_role_1; RESET ROLE; SET citus.enable_create_role_propagation TO ON; GRANT dist_role_3 TO non_dist_role_3 granted by test_admin_role; GRANT non_dist_role_4 TO dist_role_4; GRANT dist_role_3 TO dist_role_4 granted by test_admin_role; SELECT 1 FROM master_add_node('localhost', :worker_2_port); ?column? --------------------------------------------------------------------- 1 (1 row) SELECT result FROM run_command_on_all_nodes( $$ SELECT json_agg(q.* ORDER BY member) FROM ( SELECT member::regrole::text, roleid::regrole::text AS role, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text = 'dist_role_3' ) q; $$ ); result --------------------------------------------------------------------- [{"member":"dist_role_4","role":"dist_role_3","grantor":"test_admin_role","admin_option":false}, + {"member":"non_dist_role_3","role":"dist_role_3","grantor":"test_admin_role","admin_option":false}, + {"member":"test_admin_role","role":"dist_role_3","grantor":"postgres","admin_option":true}] [{"member":"dist_role_4","role":"dist_role_3","grantor":"test_admin_role","admin_option":false}, + {"member":"test_admin_role","role":"dist_role_3","grantor":"postgres","admin_option":true}] [{"member":"dist_role_4","role":"dist_role_3","grantor":"test_admin_role","admin_option":false}, + {"member":"test_admin_role","role":"dist_role_3","grantor":"postgres","admin_option":true}] (3 rows) REVOKE dist_role_3 from dist_role_4 granted by test_admin_role cascade; SELECT result FROM run_command_on_all_nodes( $$ SELECT json_agg(q.* ORDER BY member) FROM ( SELECT member::regrole::text, roleid::regrole::text AS role, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text = 'dist_role_3' order by member::regrole::text ) q; $$ ); result --------------------------------------------------------------------- [{"member":"non_dist_role_3","role":"dist_role_3","grantor":"test_admin_role","admin_option":false}, + {"member":"test_admin_role","role":"dist_role_3","grantor":"postgres","admin_option":true}] [{"member":"test_admin_role","role":"dist_role_3","grantor":"postgres","admin_option":true}] [{"member":"test_admin_role","role":"dist_role_3","grantor":"postgres","admin_option":true}] (3 rows) SELECT roleid::regrole::text AS role, member::regrole::text, (grantor::regrole::text IN ('postgres', 'non_dist_role_1', 'dist_role_1','test_admin_role')) AS grantor, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE '%dist\_%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- dist_role_1 | dist_role_2 | t | f dist_role_1 | non_dist_role_1 | t | t dist_role_1 | test_admin_role | t | t dist_role_3 | non_dist_role_3 | t | f dist_role_3 | test_admin_role | t | t non_dist_role_1 | non_dist_role_2 | t | f non_dist_role_4 | dist_role_4 | t | f (7 rows) SELECT objid::regrole FROM pg_catalog.pg_dist_object WHERE classid='pg_authid'::regclass::oid AND objid::regrole::text LIKE '%dist\_%' ORDER BY 1; objid --------------------------------------------------------------------- dist_role_1 dist_role_2 dist_role_3 dist_role_4 non_dist_role_4 (5 rows) REVOKE dist_role_3 from non_dist_role_3 granted by test_admin_role cascade; SELECT result FROM run_command_on_all_nodes( $$ SELECT json_agg(q.* ORDER BY member) FROM ( SELECT member::regrole::text, roleid::regrole::text AS role, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text = 'dist_role_3' order by member::regrole::text ) q; $$ ); result --------------------------------------------------------------------- [{"member":"test_admin_role","role":"dist_role_3","grantor":"postgres","admin_option":true}] [{"member":"test_admin_role","role":"dist_role_3","grantor":"postgres","admin_option":true}] [{"member":"test_admin_role","role":"dist_role_3","grantor":"postgres","admin_option":true}] (3 rows) revoke dist_role_3,dist_role_1 from test_admin_role cascade; drop role test_admin_role; \c - - - :worker_1_port SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE '%dist\_%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- non_dist_role_4 | dist_role_4 | postgres | f (1 row) SELECT rolname FROM pg_authid WHERE rolname LIKE '%dist\_%' ORDER BY 1; rolname --------------------------------------------------------------------- dist_role_1 dist_role_2 dist_role_3 dist_role_4 non_dist_role_4 (5 rows) \c - - - :worker_2_port SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE '%dist\_%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- non_dist_role_4 | dist_role_4 | postgres | f (1 row) SELECT rolname FROM pg_authid WHERE rolname LIKE '%dist\_%' ORDER BY 1; rolname --------------------------------------------------------------------- dist_role_1 dist_role_2 dist_role_3 dist_role_4 non_dist_role_4 (5 rows) \c - - - :master_port DROP ROLE dist_role_3, non_dist_role_3, dist_role_4, non_dist_role_4; -- test grant with multiple mixed roles CREATE ROLE dist_mixed_1; CREATE ROLE dist_mixed_2; CREATE ROLE dist_mixed_3; CREATE ROLE dist_mixed_4; SET citus.enable_create_role_propagation TO OFF; CREATE ROLE nondist_mixed_1; NOTICE: not propagating CREATE ROLE/USER commands to other nodes HINT: Connect to other nodes directly to manually create all necessary users and roles. CREATE ROLE nondist_mixed_2; NOTICE: not propagating CREATE ROLE/USER commands to other nodes HINT: Connect to other nodes directly to manually create all necessary users and roles. SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE '%dist\_mixed%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- (0 rows) SELECT objid::regrole FROM pg_catalog.pg_dist_object WHERE classid='pg_authid'::regclass::oid AND objid::regrole::text LIKE '%dist\_mixed%' ORDER BY 1; objid --------------------------------------------------------------------- dist_mixed_1 dist_mixed_2 dist_mixed_3 dist_mixed_4 (4 rows) \c - - - :worker_1_port SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE '%dist\_mixed%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- (0 rows) SELECT rolname FROM pg_authid WHERE rolname LIKE '%dist\_mixed%' ORDER BY 1; rolname --------------------------------------------------------------------- dist_mixed_1 dist_mixed_2 dist_mixed_3 dist_mixed_4 (4 rows) \c - - - :master_port SELECT master_remove_node('localhost', :worker_2_port); master_remove_node --------------------------------------------------------------------- (1 row) GRANT dist_mixed_1, dist_mixed_2, nondist_mixed_1 TO dist_mixed_3, dist_mixed_4, nondist_mixed_2; SELECT 1 FROM master_add_node('localhost', :worker_2_port); ?column? --------------------------------------------------------------------- 1 (1 row) SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE '%dist\_mixed%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- dist_mixed_1 | dist_mixed_3 | postgres | f dist_mixed_1 | dist_mixed_4 | postgres | f dist_mixed_1 | nondist_mixed_2 | postgres | f dist_mixed_2 | dist_mixed_3 | postgres | f dist_mixed_2 | dist_mixed_4 | postgres | f dist_mixed_2 | nondist_mixed_2 | postgres | f nondist_mixed_1 | dist_mixed_3 | postgres | f nondist_mixed_1 | dist_mixed_4 | postgres | f nondist_mixed_1 | nondist_mixed_2 | postgres | f (9 rows) SELECT objid::regrole FROM pg_catalog.pg_dist_object WHERE classid='pg_authid'::regclass::oid AND objid::regrole::text LIKE '%dist\_mixed%' ORDER BY 1; objid --------------------------------------------------------------------- dist_mixed_1 dist_mixed_2 dist_mixed_3 dist_mixed_4 nondist_mixed_1 (5 rows) \c - - - :worker_1_port SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE '%dist\_mixed%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- dist_mixed_1 | dist_mixed_3 | postgres | f dist_mixed_1 | dist_mixed_4 | postgres | f dist_mixed_2 | dist_mixed_3 | postgres | f dist_mixed_2 | dist_mixed_4 | postgres | f nondist_mixed_1 | dist_mixed_3 | postgres | f nondist_mixed_1 | dist_mixed_4 | postgres | f (6 rows) SELECT rolname FROM pg_authid WHERE rolname LIKE '%dist\_mixed%' ORDER BY 1; rolname --------------------------------------------------------------------- dist_mixed_1 dist_mixed_2 dist_mixed_3 dist_mixed_4 nondist_mixed_1 (5 rows) \c - - - :worker_2_port SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE '%dist\_mixed%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- dist_mixed_1 | dist_mixed_3 | postgres | f dist_mixed_1 | dist_mixed_4 | postgres | f dist_mixed_2 | dist_mixed_3 | postgres | f dist_mixed_2 | dist_mixed_4 | postgres | f nondist_mixed_1 | dist_mixed_3 | postgres | f nondist_mixed_1 | dist_mixed_4 | postgres | f (6 rows) SELECT rolname FROM pg_authid WHERE rolname LIKE '%dist\_mixed%' ORDER BY 1; rolname --------------------------------------------------------------------- dist_mixed_1 dist_mixed_2 dist_mixed_3 dist_mixed_4 nondist_mixed_1 (5 rows) \c - - - :master_port DROP ROLE dist_mixed_1, dist_mixed_2, dist_mixed_3, dist_mixed_4, nondist_mixed_1, nondist_mixed_2; -- test drop multiple roles with non-distributed roles SELECT objid::regrole FROM pg_catalog.pg_dist_object WHERE classid='pg_authid'::regclass::oid AND objid::regrole::text LIKE '%dist%' ORDER BY 1; objid --------------------------------------------------------------------- dist_role_1 dist_role_2 (2 rows) SELECT rolname FROM pg_authid WHERE rolname LIKE '%dist%' ORDER BY 1; rolname --------------------------------------------------------------------- dist_role_1 dist_role_2 non_dist_role_1 non_dist_role_2 (4 rows) \c - - - :worker_1_port SELECT rolname FROM pg_authid WHERE rolname LIKE '%dist%' ORDER BY 1; rolname --------------------------------------------------------------------- dist_role_1 dist_role_2 (2 rows) \c - - - :master_port DROP ROLE dist_role_1, non_dist_role_1, dist_role_2, non_dist_role_2; SELECT objid::regrole FROM pg_catalog.pg_dist_object WHERE classid='pg_authid'::regclass::oid AND objid::regrole::text LIKE '%dist%' ORDER BY 1; objid --------------------------------------------------------------------- (0 rows) SELECT rolname FROM pg_authid WHERE rolname LIKE '%dist%' ORDER BY 1; rolname --------------------------------------------------------------------- (0 rows) \c - - - :worker_1_port SELECT rolname FROM pg_authid WHERE rolname LIKE '%dist%' ORDER BY 1; rolname --------------------------------------------------------------------- (0 rows) \c - - - :master_port -- test alter part of create or alter role SELECT master_remove_node('localhost', :worker_2_port); master_remove_node --------------------------------------------------------------------- (1 row) DROP ROLE create_role, create_role_2; \c - - - :worker_2_port SELECT rolname, rolcanlogin FROM pg_authid WHERE rolname = 'create_role' OR rolname = 'create_role_2' ORDER BY rolname; rolname | rolcanlogin --------------------------------------------------------------------- create_role | f create_role_2 | f (2 rows) \c - - - :master_port CREATE ROLE create_role LOGIN; SELECT 1 FROM master_add_node('localhost', :worker_2_port); ?column? --------------------------------------------------------------------- 1 (1 row) CREATE ROLE create_role_2 LOGIN; \c - - - :worker_2_port SELECT rolname, rolcanlogin FROM pg_authid WHERE rolname = 'create_role' OR rolname = 'create_role_2' ORDER BY rolname; rolname | rolcanlogin --------------------------------------------------------------------- create_role | t create_role_2 | t (2 rows) \c - - - :master_port -- test cascading grants SET citus.enable_create_role_propagation TO OFF; CREATE ROLE nondist_cascade_1; NOTICE: not propagating CREATE ROLE/USER commands to other nodes HINT: Connect to other nodes directly to manually create all necessary users and roles. CREATE ROLE nondist_cascade_2; NOTICE: not propagating CREATE ROLE/USER commands to other nodes HINT: Connect to other nodes directly to manually create all necessary users and roles. CREATE ROLE nondist_cascade_3; NOTICE: not propagating CREATE ROLE/USER commands to other nodes HINT: Connect to other nodes directly to manually create all necessary users and roles. SET citus.enable_create_role_propagation TO ON; CREATE ROLE dist_cascade; GRANT nondist_cascade_1 TO nondist_cascade_2; GRANT nondist_cascade_2 TO nondist_cascade_3; SELECT objid::regrole FROM pg_catalog.pg_dist_object WHERE classid='pg_authid'::regclass::oid AND objid::regrole::text LIKE '%cascade%' ORDER BY 1; objid --------------------------------------------------------------------- dist_cascade (1 row) SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE '%cascade%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- nondist_cascade_1 | nondist_cascade_2 | postgres | f nondist_cascade_2 | nondist_cascade_3 | postgres | f (2 rows) \c - - - :worker_1_port SELECT rolname FROM pg_authid WHERE rolname LIKE '%cascade%' ORDER BY 1; rolname --------------------------------------------------------------------- dist_cascade (1 row) SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE '%cascade%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- (0 rows) \c - - - :master_port SELECT master_remove_node('localhost', :worker_2_port); master_remove_node --------------------------------------------------------------------- (1 row) GRANT nondist_cascade_3 TO dist_cascade; SELECT 1 FROM master_add_node('localhost', :worker_2_port); ?column? --------------------------------------------------------------------- 1 (1 row) SELECT objid::regrole FROM pg_catalog.pg_dist_object WHERE classid='pg_authid'::regclass::oid AND objid::regrole::text LIKE '%cascade%' ORDER BY 1; objid --------------------------------------------------------------------- nondist_cascade_1 nondist_cascade_2 nondist_cascade_3 dist_cascade (4 rows) SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE '%cascade%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- nondist_cascade_1 | nondist_cascade_2 | postgres | f nondist_cascade_2 | nondist_cascade_3 | postgres | f nondist_cascade_3 | dist_cascade | postgres | f (3 rows) \c - - - :worker_1_port SELECT rolname FROM pg_authid WHERE rolname LIKE '%cascade%' ORDER BY 1; rolname --------------------------------------------------------------------- dist_cascade nondist_cascade_1 nondist_cascade_2 nondist_cascade_3 (4 rows) SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE '%cascade%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- nondist_cascade_1 | nondist_cascade_2 | postgres | f nondist_cascade_2 | nondist_cascade_3 | postgres | f nondist_cascade_3 | dist_cascade | postgres | f (3 rows) \c - - - :worker_2_port SELECT rolname FROM pg_authid WHERE rolname LIKE '%cascade%' ORDER BY 1; rolname --------------------------------------------------------------------- dist_cascade nondist_cascade_1 nondist_cascade_2 nondist_cascade_3 (4 rows) SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE '%cascade%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- nondist_cascade_1 | nondist_cascade_2 | postgres | f nondist_cascade_2 | nondist_cascade_3 | postgres | f nondist_cascade_3 | dist_cascade | postgres | f (3 rows) \c - - - :master_port DROP ROLE create_role, create_role_2, create_group, create_group_2, create_user, create_user_2, create_role_with_nothing, create_role_sysid, "create_role'edge", "create_role""edge"; -- test grant non-existing roles CREATE ROLE existing_role_1; CREATE ROLE existing_role_2; SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE '%existing%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- (0 rows) GRANT existing_role_1, nonexisting_role_1 TO existing_role_2, nonexisting_role_2; ERROR: role "nonexisting_role_2" does not exist SELECT roleid::regrole::text AS role, member::regrole::text, grantor::regrole::text, admin_option FROM pg_auth_members WHERE roleid::regrole::text LIKE '%existing%' ORDER BY 1, 2; role | member | grantor | admin_option --------------------------------------------------------------------- (0 rows) -- test drop non-existing roles SELECT objid::regrole FROM pg_catalog.pg_dist_object WHERE classid='pg_authid'::regclass::oid AND objid::regrole::text LIKE '%existing%' ORDER BY 1; objid --------------------------------------------------------------------- existing_role_1 existing_role_2 (2 rows) SELECT rolname FROM pg_authid WHERE rolname LIKE '%existing%' ORDER BY 1; rolname --------------------------------------------------------------------- existing_role_1 existing_role_2 (2 rows) \c - - - :worker_1_port SELECT rolname FROM pg_authid WHERE rolname LIKE '%existing%' ORDER BY 1; rolname --------------------------------------------------------------------- existing_role_1 existing_role_2 (2 rows) \c - - - :master_port DROP ROLE existing_role_1, existing_role_2, nonexisting_role_1, nonexisting_role_2; ERROR: role "nonexisting_role_1" does not exist SELECT objid::regrole FROM pg_catalog.pg_dist_object WHERE classid='pg_authid'::regclass::oid AND objid::regrole::text LIKE '%existing%' ORDER BY 1; objid --------------------------------------------------------------------- existing_role_1 existing_role_2 (2 rows) SELECT rolname FROM pg_authid WHERE rolname LIKE '%existing%' ORDER BY 1; rolname --------------------------------------------------------------------- existing_role_1 existing_role_2 (2 rows) \c - - - :worker_1_port SELECT rolname FROM pg_authid WHERE rolname LIKE '%existing%' ORDER BY 1; rolname --------------------------------------------------------------------- existing_role_1 existing_role_2 (2 rows) \c - - - :master_port DROP ROLE IF EXISTS existing_role_1, existing_role_2, nonexisting_role_1, nonexisting_role_2; NOTICE: role "nonexisting_role_1" does not exist, skipping NOTICE: role "nonexisting_role_2" does not exist, skipping SELECT objid::regrole FROM pg_catalog.pg_dist_object WHERE classid='pg_authid'::regclass::oid AND objid::regrole::text LIKE '%existing%' ORDER BY 1; objid --------------------------------------------------------------------- (0 rows) SELECT rolname FROM pg_authid WHERE rolname LIKE '%existing%' ORDER BY 1; rolname --------------------------------------------------------------------- (0 rows) \c - - - :worker_1_port SELECT rolname FROM pg_authid WHERE rolname LIKE '%existing%' ORDER BY 1; rolname --------------------------------------------------------------------- (0 rows) \c - - - :master_port DROP ROLE nondist_cascade_1, nondist_cascade_2, nondist_cascade_3, dist_cascade;