CREATE SCHEMA alter_role;
CREATE SCHEMA ",CitUs,.TeeN!?";
-- test if the passowrd of the extension owner can be upgraded
ALTER ROLE CURRENT_USER CONNECTION LIMIT -1 PASSWORD 'password123' VALID UNTIL 'infinity';
SELECT run_command_on_workers($$SELECT row(rolname, rolsuper, rolinherit,  rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, EXTRACT (year FROM rolvaliduntil)) FROM pg_authid WHERE rolname = current_user$$);
                   run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,"(postgres,t,t,t,t,t,t,t,-1,Infinity)")
 (localhost,57638,t,"(postgres,t,t,t,t,t,t,t,-1,Infinity)")
(2 rows)

SELECT workers.result = pg_authid.rolpassword AS password_is_same FROM run_command_on_workers($$SELECT rolpassword FROM pg_authid WHERE rolname = current_user$$) workers, pg_authid WHERE pg_authid.rolname = current_user;
 password_is_same
---------------------------------------------------------------------
 t
 t
(2 rows)

-- test if the password and some connection settings are propagated when a node gets added
ALTER ROLE CURRENT_USER WITH CONNECTION LIMIT 66 VALID UNTIL '2032-05-05' PASSWORD 'password456';
SELECT row(rolname, rolsuper, rolinherit,  rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, rolpassword, EXTRACT (year FROM rolvaliduntil)) FROM pg_authid WHERE rolname = 'alter_role_1';
 row
---------------------------------------------------------------------
(0 rows)

SELECT run_command_on_workers($$SELECT row(rolname, rolsuper, rolinherit,  rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, EXTRACT (year FROM rolvaliduntil)) FROM pg_authid WHERE rolname = current_user$$);
                 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,"(postgres,t,t,t,t,t,t,t,66,2032)")
 (localhost,57638,t,"(postgres,t,t,t,t,t,t,t,66,2032)")
(2 rows)

SELECT workers.result = pg_authid.rolpassword AS password_is_same FROM run_command_on_workers($$SELECT rolpassword FROM pg_authid WHERE rolname = current_user$$) workers, pg_authid WHERE pg_authid.rolname = current_user;
 password_is_same
---------------------------------------------------------------------
 t
 t
(2 rows)

SELECT master_remove_node('localhost', :worker_1_port);
 master_remove_node
---------------------------------------------------------------------

(1 row)

ALTER ROLE CURRENT_USER WITH CONNECTION LIMIT 0 VALID UNTIL '2052-05-05' PASSWORD 'password789';
SELECT row(rolname, rolsuper, rolinherit,  rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, rolpassword, EXTRACT (year FROM rolvaliduntil)) FROM pg_authid WHERE rolname = 'alter_role_1';
 row
---------------------------------------------------------------------
(0 rows)

SELECT run_command_on_workers($$SELECT row(rolname, rolsuper, rolinherit,  rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, EXTRACT (year FROM rolvaliduntil)) FROM pg_authid WHERE rolname = current_user$$);
                run_command_on_workers
---------------------------------------------------------------------
 (localhost,57638,t,"(postgres,t,t,t,t,t,t,t,0,2052)")
(1 row)

SELECT workers.result = pg_authid.rolpassword AS password_is_same FROM run_command_on_workers($$SELECT rolpassword FROM pg_authid WHERE rolname = current_user$$) workers, pg_authid WHERE pg_authid.rolname = current_user;
 password_is_same
---------------------------------------------------------------------
 t
(1 row)

SELECT 1 FROM master_add_node('localhost', :worker_1_port);
 ?column?
---------------------------------------------------------------------
        1
(1 row)

SELECT row(rolname, rolsuper, rolinherit,  rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, rolpassword, EXTRACT (year FROM rolvaliduntil)) FROM pg_authid WHERE rolname = 'alter_role_1';
 row
---------------------------------------------------------------------
(0 rows)

SELECT run_command_on_workers($$SELECT row(rolname, rolsuper, rolinherit,  rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, EXTRACT (year FROM rolvaliduntil)) FROM pg_authid WHERE rolname = current_user$$);
                run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,"(postgres,t,t,t,t,t,t,t,0,2052)")
 (localhost,57638,t,"(postgres,t,t,t,t,t,t,t,0,2052)")
(2 rows)

SELECT workers.result = pg_authid.rolpassword AS password_is_same FROM run_command_on_workers($$SELECT rolpassword FROM pg_authid WHERE rolname = current_user$$) workers, pg_authid WHERE pg_authid.rolname = current_user;
 password_is_same
---------------------------------------------------------------------
 t
 t
(2 rows)

-- check user, database and postgres wide SET settings.
-- pre check
SELECT run_command_on_workers('SHOW enable_hashjoin');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,on)
 (localhost,57638,t,on)
(2 rows)

SELECT run_command_on_workers('SHOW enable_indexonlyscan');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,on)
 (localhost,57638,t,on)
(2 rows)

SELECT run_command_on_workers('SHOW enable_hashagg');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,on)
 (localhost,57638,t,on)
(2 rows)

-- remove 1 node to verify settings are copied when the node gets added back
SELECT master_remove_node('localhost', :worker_1_port);
 master_remove_node
---------------------------------------------------------------------

(1 row)

-- change a setting for all users
ALTER ROLE ALL SET enable_hashjoin TO FALSE;
SELECT run_command_on_workers('SHOW enable_hashjoin');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57638,t,off)
(1 row)

ALTER ROLE ALL IN DATABASE regression SET enable_indexonlyscan TO FALSE;
SELECT run_command_on_workers('SHOW enable_indexonlyscan');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57638,t,off)
(1 row)

-- alter configuration_parameter defaults for a user
ALTER ROLE CURRENT_USER SET enable_hashagg TO FALSE;
SELECT run_command_on_workers('SHOW enable_hashagg');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57638,t,off)
(1 row)

-- provide a list of values in a supported configuration
ALTER ROLE CURRENT_USER SET search_path TO ",CitUs,.TeeN!?", alter_role, public;
-- test user defined GUCs that appear to be a list, but instead a single string
ALTER ROLE ALL SET public.myguc TO "Hello, World";
-- test for configuration values that should not be downcased even when unquoted
ALTER ROLE CURRENT_USER SET lc_messages TO 'C';
-- add worker and check all settings are copied
SELECT 1 FROM master_add_node('localhost', :worker_1_port);
 ?column?
---------------------------------------------------------------------
        1
(1 row)

SELECT run_command_on_workers('SHOW enable_hashjoin');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,off)
 (localhost,57638,t,off)
(2 rows)

SELECT run_command_on_workers('SHOW enable_indexonlyscan');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,off)
 (localhost,57638,t,off)
(2 rows)

SELECT run_command_on_workers('SHOW enable_hashagg');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,off)
 (localhost,57638,t,off)
(2 rows)

SELECT run_command_on_workers('SHOW search_path');
                    run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,""",CitUs,.TeeN!?"", alter_role, public")
 (localhost,57638,t,""",CitUs,.TeeN!?"", alter_role, public")
(2 rows)

SELECT run_command_on_workers('SHOW lc_messages');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,C)
 (localhost,57638,t,C)
(2 rows)

SELECT run_command_on_workers('SHOW public.myguc');
       run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,"Hello, World")
 (localhost,57638,t,"Hello, World")
(2 rows)

-- reset to default values
ALTER ROLE CURRENT_USER RESET enable_hashagg;
SELECT run_command_on_workers('SHOW enable_hashagg');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,on)
 (localhost,57638,t,on)
(2 rows)

-- RESET ALL with IN DATABASE clause
ALTER ROLE ALL RESET ALL;
-- post check 1 - should have settings reset except for database specific settings
SELECT run_command_on_workers('SHOW enable_hashjoin');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,on)
 (localhost,57638,t,on)
(2 rows)

SELECT run_command_on_workers('SHOW enable_indexonlyscan');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,off)
 (localhost,57638,t,off)
(2 rows)

SELECT run_command_on_workers('SHOW enable_hashagg');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,on)
 (localhost,57638,t,on)
(2 rows)

ALTER ROLE ALL IN DATABASE regression RESET ALL;
-- post check 2 - should have all settings reset
SELECT run_command_on_workers('SHOW enable_hashjoin');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,on)
 (localhost,57638,t,on)
(2 rows)

SELECT run_command_on_workers('SHOW enable_indexonlyscan');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,on)
 (localhost,57638,t,on)
(2 rows)

SELECT run_command_on_workers('SHOW enable_hashagg');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,on)
 (localhost,57638,t,on)
(2 rows)

-- check that ALTER ROLE SET is not propagated when scoped to a different database
-- also test case sensitivity
CREATE DATABASE "REGRESSION";
NOTICE:  Citus partially supports CREATE DATABASE for distributed databases
DETAIL:  Citus does not propagate CREATE DATABASE command to other nodes
HINT:  You can manually create a database and its extensions on other nodes.
ALTER ROLE CURRENT_USER IN DATABASE "REGRESSION" SET public.myguc TO "Hello from coordinator only";
SELECT d.datname, r.setconfig FROM pg_db_role_setting r LEFT JOIN pg_database d ON r.setdatabase=d.oid WHERE r.setconfig::text LIKE '%Hello from coordinator only%';
  datname   |                  setconfig
---------------------------------------------------------------------
 REGRESSION | {"public.myguc=Hello from coordinator only"}
(1 row)

SELECT run_command_on_workers($$SELECT json_agg((d.datname, r.setconfig)) FROM pg_db_role_setting r LEFT JOIN pg_database d ON r.setdatabase=d.oid WHERE r.setconfig::text LIKE '%Hello from coordinator only%'$$);
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,"")
 (localhost,57638,t,"")
(2 rows)

DROP DATABASE "REGRESSION";
-- make sure alter role set is not propagated when the feature is deliberately turned off
SET citus.enable_alter_role_set_propagation TO off;
-- remove 1 node to verify settings are NOT copied when the node gets added back
SELECT master_remove_node('localhost', :worker_1_port);
 master_remove_node
---------------------------------------------------------------------

(1 row)

ALTER ROLE ALL SET enable_hashjoin TO FALSE;
SELECT 1 FROM master_add_node('localhost', :worker_1_port);
 ?column?
---------------------------------------------------------------------
        1
(1 row)

SELECT run_command_on_workers('SHOW enable_hashjoin');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,on)
 (localhost,57638,t,on)
(2 rows)

ALTER ROLE ALL RESET enable_hashjoin;
SELECT run_command_on_workers('SHOW enable_hashjoin');
 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,on)
 (localhost,57638,t,on)
(2 rows)

-- check altering search path won't cause public shards being not found
CREATE TABLE test_search_path(a int);
SELECT create_distributed_table('test_search_path', 'a');
 create_distributed_table
---------------------------------------------------------------------

(1 row)

CREATE SCHEMA test_sp;
ALTER USER current_user SET search_path TO test_sp;
SELECT COUNT(*) FROM public.test_search_path;
 count
---------------------------------------------------------------------
     0
(1 row)

ALTER USER current_user RESET search_path;
-- test empty/null password: it is treated the same as no password
SET password_encryption TO md5;
CREATE ROLE new_role;
SELECT workers.result AS worker_password, pg_authid.rolpassword AS coord_password FROM run_command_on_workers($$SELECT rolpassword FROM pg_authid WHERE rolname = 'new_role'$$) workers, pg_authid WHERE pg_authid.rolname = 'new_role';
 worker_password | coord_password
---------------------------------------------------------------------
                 |
                 |
(2 rows)

ALTER ROLE new_role PASSWORD '';
NOTICE:  empty string is not a valid password, clearing password
SELECT workers.result AS worker_password, pg_authid.rolpassword AS coord_password FROM run_command_on_workers($$SELECT rolpassword FROM pg_authid WHERE rolname = 'new_role'$$) workers, pg_authid WHERE pg_authid.rolname = 'new_role';
 worker_password | coord_password
---------------------------------------------------------------------
                 |
                 |
(2 rows)

SET client_min_messages TO ERROR;
ALTER ROLE new_role PASSWORD 'new_password';
RESET client_min_messages;
SELECT workers.result AS worker_password, pg_authid.rolpassword AS coord_password, workers.result = pg_authid.rolpassword AS password_is_same FROM run_command_on_workers($$SELECT rolpassword FROM pg_authid WHERE rolname = 'new_role'$$) workers, pg_authid WHERE pg_authid.rolname = 'new_role';
           worker_password           |           coord_password            | password_is_same
---------------------------------------------------------------------
 md51a28da0f1a2416525eec435bdce8cbbe | md51a28da0f1a2416525eec435bdce8cbbe | t
 md51a28da0f1a2416525eec435bdce8cbbe | md51a28da0f1a2416525eec435bdce8cbbe | t
(2 rows)

ALTER ROLE new_role PASSWORD NULL;
SELECT workers.result AS worker_password, pg_authid.rolpassword AS coord_password FROM run_command_on_workers($$SELECT rolpassword FROM pg_authid WHERE rolname = 'new_role'$$) workers, pg_authid WHERE pg_authid.rolname = 'new_role';
 worker_password | coord_password
---------------------------------------------------------------------
                 |
                 |
(2 rows)

RESET password_encryption;
DROP ROLE new_role;
drop user if exists test1 ;
NOTICE:  role "test1" does not exist, skipping
create user test1;
SELECT run_command_on_workers($$SELECT row() FROM pg_roles WHERE rolname = 'test1'$$);
  run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,"()")
 (localhost,57638,t,"()")
(2 rows)

alter user test1 with encrypted password 'test1' nosuperuser noinherit nocreaterole nocreatedb nologin noreplication nobypassrls connection limit -1 valid until 'infinity';
SELECT run_command_on_workers($$SELECT row(rolname, rolsuper, rolinherit,  rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, EXTRACT (year FROM rolvaliduntil)) FROM pg_authid WHERE rolname = 'test1'$$);
                 run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,"(test1,f,f,f,f,f,f,f,-1,Infinity)")
 (localhost,57638,t,"(test1,f,f,f,f,f,f,f,-1,Infinity)")
(2 rows)

alter user test1 with password NULL superuser inherit createrole createdb login replication bypassrls connection limit 10 valid until '2019-01-01';
SELECT run_command_on_workers($$SELECT row(rolname, rolsuper, rolinherit,  rolcreaterole, rolcreatedb, rolcanlogin, rolreplication, rolbypassrls, rolconnlimit, EXTRACT (year FROM rolvaliduntil)) FROM pg_authid WHERE rolname = 'test1'$$);
               run_command_on_workers
---------------------------------------------------------------------
 (localhost,57637,t,"(test1,t,t,t,t,t,t,t,10,2019)")
 (localhost,57638,t,"(test1,t,t,t,t,t,t,t,10,2019)")
(2 rows)

SET citus.enable_alter_role_set_propagation TO on;
SET citus.log_remote_commands = true;
set citus.grep_remote_commands = '%ALTER ROLE%';
ALTER USER test1 SET timezone TO 'America/New_York';
NOTICE:  issuing ALTER ROLE test1 SET timezone = 'America/New_York'
DETAIL:  on server postgres@localhost:xxxxx connectionId: xxxxxxx
NOTICE:  issuing ALTER ROLE test1 SET timezone = 'America/New_York'
DETAIL:  on server postgres@localhost:xxxxx connectionId: xxxxxxx
ALTER USER test1 SET work_mem TO '64MB';
NOTICE:  issuing ALTER ROLE test1 SET work_mem = '64MB'
DETAIL:  on server postgres@localhost:xxxxx connectionId: xxxxxxx
NOTICE:  issuing ALTER ROLE test1 SET work_mem = '64MB'
DETAIL:  on server postgres@localhost:xxxxx connectionId: xxxxxxx
ALTER USER test1 SET random_page_cost TO 1.5;
NOTICE:  issuing ALTER ROLE test1 SET random_page_cost = 1.5
DETAIL:  on server postgres@localhost:xxxxx connectionId: xxxxxxx
NOTICE:  issuing ALTER ROLE test1 SET random_page_cost = 1.5
DETAIL:  on server postgres@localhost:xxxxx connectionId: xxxxxxx
alter user test1 rename to test2;
NOTICE:  issuing ALTER ROLE test1 RENAME TO test2;
DETAIL:  on server postgres@localhost:xxxxx connectionId: xxxxxxx
NOTICE:  issuing ALTER ROLE test1 RENAME TO test2;
DETAIL:  on server postgres@localhost:xxxxx connectionId: xxxxxxx
drop user test2;
SET citus.log_remote_commands = false;
DROP TABLE test_search_path;
DROP SCHEMA alter_role, ",CitUs,.TeeN!?", test_sp CASCADE;
