mirror of https://github.com/citusdata/citus.git
Adds Grant Role support into 2PC
parent
d940cfa992
commit
20dc90289b
|
@ -43,6 +43,7 @@
|
||||||
#include "foreign/foreign.h"
|
#include "foreign/foreign.h"
|
||||||
#include "lib/stringinfo.h"
|
#include "lib/stringinfo.h"
|
||||||
#include "nodes/makefuncs.h"
|
#include "nodes/makefuncs.h"
|
||||||
|
#include "nodes/nodes.h"
|
||||||
#include "nodes/parsenodes.h"
|
#include "nodes/parsenodes.h"
|
||||||
#include "nodes/pg_list.h"
|
#include "nodes/pg_list.h"
|
||||||
#include "postmaster/postmaster.h"
|
#include "postmaster/postmaster.h"
|
||||||
|
@ -95,6 +96,18 @@
|
||||||
"SELECT citus_internal.mark_object_distributed(%d, %s, %d)"
|
"SELECT citus_internal.mark_object_distributed(%d, %s, %d)"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct TwoPcStatementInfo
|
||||||
|
{
|
||||||
|
int statementType;
|
||||||
|
bool markAsDistributed;
|
||||||
|
} TwoPcStatementInfo;
|
||||||
|
|
||||||
|
const TwoPcStatementInfo twoPcSupportedStatements[] = {
|
||||||
|
{ T_GrantRoleStmt, false },
|
||||||
|
{ T_CreateRoleStmt, true }
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
bool EnableDDLPropagation = true; /* ddl propagation is enabled */
|
bool EnableDDLPropagation = true; /* ddl propagation is enabled */
|
||||||
int CreateObjectPropagationMode = CREATE_OBJECT_PROPAGATION_IMMEDIATE;
|
int CreateObjectPropagationMode = CREATE_OBJECT_PROPAGATION_IMMEDIATE;
|
||||||
PropSetCmdBehavior PropagateSetCommands = PROPSETCMD_NONE; /* SET prop off */
|
PropSetCmdBehavior PropagateSetCommands = PROPSETCMD_NONE; /* SET prop off */
|
||||||
|
@ -124,6 +137,8 @@ static bool IsDropSchemaOrDB(Node *parsetree);
|
||||||
static bool ShouldCheckUndistributeCitusLocalTables(void);
|
static bool ShouldCheckUndistributeCitusLocalTables(void);
|
||||||
static void RunPreprocessMainDBCommand(Node *parsetree, const char *queryString);
|
static void RunPreprocessMainDBCommand(Node *parsetree, const char *queryString);
|
||||||
static void RunPostprocessMainDBCommand(Node *parsetree);
|
static void RunPostprocessMainDBCommand(Node *parsetree);
|
||||||
|
static bool IsStatementSupportedIn2Pc(Node *parsetree);
|
||||||
|
static bool IsStatementMarkDistributedFor2PC(Node *parsetree);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ProcessUtilityParseTree is a convenience method to create a PlannedStmt out of
|
* ProcessUtilityParseTree is a convenience method to create a PlannedStmt out of
|
||||||
|
@ -1603,20 +1618,22 @@ DropSchemaOrDBInProgress(void)
|
||||||
static void
|
static void
|
||||||
RunPreprocessMainDBCommand(Node *parsetree, const char *queryString)
|
RunPreprocessMainDBCommand(Node *parsetree, const char *queryString)
|
||||||
{
|
{
|
||||||
if (IsA(parsetree, CreateRoleStmt))
|
if (!IsStatementSupportedIn2Pc(parsetree))
|
||||||
{
|
{
|
||||||
StringInfo mainDBQuery = makeStringInfo();
|
return;
|
||||||
appendStringInfo(mainDBQuery,
|
|
||||||
START_MANAGEMENT_TRANSACTION,
|
|
||||||
GetCurrentFullTransactionId().value);
|
|
||||||
RunCitusMainDBQuery(mainDBQuery->data);
|
|
||||||
mainDBQuery = makeStringInfo();
|
|
||||||
appendStringInfo(mainDBQuery,
|
|
||||||
EXECUTE_COMMAND_ON_REMOTE_NODES_AS_USER,
|
|
||||||
quote_literal_cstr(queryString),
|
|
||||||
quote_literal_cstr(CurrentUserName()));
|
|
||||||
RunCitusMainDBQuery(mainDBQuery->data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
StringInfo mainDBQuery = makeStringInfo();
|
||||||
|
appendStringInfo(mainDBQuery,
|
||||||
|
START_MANAGEMENT_TRANSACTION,
|
||||||
|
GetCurrentFullTransactionId().value);
|
||||||
|
RunCitusMainDBQuery(mainDBQuery->data);
|
||||||
|
mainDBQuery = makeStringInfo();
|
||||||
|
appendStringInfo(mainDBQuery,
|
||||||
|
EXECUTE_COMMAND_ON_REMOTE_NODES_AS_USER,
|
||||||
|
quote_literal_cstr(queryString),
|
||||||
|
quote_literal_cstr(CurrentUserName()));
|
||||||
|
RunCitusMainDBQuery(mainDBQuery->data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1627,6 +1644,12 @@ RunPreprocessMainDBCommand(Node *parsetree, const char *queryString)
|
||||||
static void
|
static void
|
||||||
RunPostprocessMainDBCommand(Node *parsetree)
|
RunPostprocessMainDBCommand(Node *parsetree)
|
||||||
{
|
{
|
||||||
|
if (!IsStatementSupportedIn2Pc(parsetree) ||
|
||||||
|
!IsStatementMarkDistributedFor2PC(parsetree))
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (IsA(parsetree, CreateRoleStmt))
|
if (IsA(parsetree, CreateRoleStmt))
|
||||||
{
|
{
|
||||||
StringInfo mainDBQuery = makeStringInfo();
|
StringInfo mainDBQuery = makeStringInfo();
|
||||||
|
@ -1640,3 +1663,45 @@ RunPostprocessMainDBCommand(Node *parsetree)
|
||||||
RunCitusMainDBQuery(mainDBQuery->data);
|
RunCitusMainDBQuery(mainDBQuery->data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IsStatementSupportedIn2Pc returns true if the statement is supported in 2pc
|
||||||
|
*/
|
||||||
|
|
||||||
|
static bool
|
||||||
|
IsStatementSupportedIn2Pc(Node *parsetree)
|
||||||
|
{
|
||||||
|
NodeTag type = nodeTag(parsetree);
|
||||||
|
|
||||||
|
for (int i = 0; i < sizeof(twoPcSupportedStatements) /
|
||||||
|
sizeof(twoPcSupportedStatements[0]); i++)
|
||||||
|
{
|
||||||
|
if (type == twoPcSupportedStatements[i].statementType)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* IsStatementMarkDistributedFor2PC returns true if the statement should be marked
|
||||||
|
* as distributed in 2pc
|
||||||
|
*/
|
||||||
|
static bool
|
||||||
|
IsStatementMarkDistributedFor2PC(Node *parsetree)
|
||||||
|
{
|
||||||
|
NodeTag type = nodeTag(parsetree);
|
||||||
|
|
||||||
|
for (int i = 0; i < sizeof(twoPcSupportedStatements) /
|
||||||
|
sizeof(twoPcSupportedStatements[0]); i++)
|
||||||
|
{
|
||||||
|
if (type == twoPcSupportedStatements[i].statementType)
|
||||||
|
{
|
||||||
|
return twoPcSupportedStatements[i].markAsDistributed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
|
@ -109,6 +109,7 @@ test: undistribute_table
|
||||||
test: run_command_on_all_nodes
|
test: run_command_on_all_nodes
|
||||||
test: background_task_queue_monitor
|
test: background_task_queue_monitor
|
||||||
test: other_databases
|
test: other_databases
|
||||||
|
test: grant_role_2pc
|
||||||
|
|
||||||
# Causal clock test
|
# Causal clock test
|
||||||
test: clock
|
test: clock
|
||||||
|
|
|
@ -0,0 +1,131 @@
|
||||||
|
|
||||||
|
|
||||||
|
CREATE SCHEMA grant_role2pc;
|
||||||
|
|
||||||
|
SET search_path TO grant_role2pc;
|
||||||
|
|
||||||
|
set citus.enable_create_database_propagation to on;
|
||||||
|
|
||||||
|
|
||||||
|
set citus.log_remote_commands to on;
|
||||||
|
|
||||||
|
|
||||||
|
SET citus.next_shard_id TO 10231023;
|
||||||
|
|
||||||
|
CREATE DATABASE grant_role2pc_db;
|
||||||
|
|
||||||
|
revoke connect,temp,temporary,create on database grant_role2pc_db from public;
|
||||||
|
|
||||||
|
\c grant_role2pc_db
|
||||||
|
SHOW citus.main_db;
|
||||||
|
|
||||||
|
-- check that empty citus.superuser gives error
|
||||||
|
SET citus.superuser TO '';
|
||||||
|
CREATE USER empty_superuser;
|
||||||
|
SET citus.superuser TO 'postgres';
|
||||||
|
|
||||||
|
CREATE USER grant_role2pc_user1;
|
||||||
|
CREATE USER grant_role2pc_user2;
|
||||||
|
CREATE USER grant_role2pc_user3;
|
||||||
|
CREATE USER grant_role2pc_user4;
|
||||||
|
CREATE USER grant_role2pc_user5;
|
||||||
|
CREATE USER grant_role2pc_user6;
|
||||||
|
CREATE USER grant_role2pc_user7;
|
||||||
|
|
||||||
|
|
||||||
|
\c regression
|
||||||
|
|
||||||
|
SELECT * FROM public.check_database_privileges('grant_role2pc_user2', 'grant_role2pc_db', ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
|
||||||
|
|
||||||
|
grant create,connect,temporary,temp on database grant_role2pc_db to grant_role2pc_user1;
|
||||||
|
|
||||||
|
\c grant_role2pc_db
|
||||||
|
|
||||||
|
grant grant_role2pc_user1 to grant_role2pc_user2;
|
||||||
|
|
||||||
|
\c regression
|
||||||
|
|
||||||
|
|
||||||
|
SELECT * FROM public.check_database_privileges('grant_role2pc_user2', 'grant_role2pc_db', ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
|
||||||
|
|
||||||
|
|
||||||
|
\c grant_role2pc_db
|
||||||
|
--test grant under transactional context with multiple operations
|
||||||
|
BEGIN;
|
||||||
|
grant grant_role2pc_user1 to grant_role2pc_user3;
|
||||||
|
grant grant_role2pc_user1 to grant_role2pc_user4;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
grant grant_role2pc_user1 to grant_role2pc_user5;
|
||||||
|
grant grant_role2pc_user1 to grant_role2pc_user6;
|
||||||
|
ROLLBACK;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
grant grant_role2pc_user1 to grant_role2pc_user7;
|
||||||
|
SELECT 1/0;
|
||||||
|
commit;
|
||||||
|
|
||||||
|
|
||||||
|
\c regression
|
||||||
|
|
||||||
|
SELECT * FROM public.check_database_privileges('grant_role2pc_user3', 'grant_role2pc_db', ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
|
||||||
|
SELECT * FROM public.check_database_privileges('grant_role2pc_user4', 'grant_role2pc_db', ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
|
||||||
|
SELECT * FROM public.check_database_privileges('grant_role2pc_user5', 'grant_role2pc_db', ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
|
||||||
|
SELECT * FROM public.check_database_privileges('grant_role2pc_user6', 'grant_role2pc_db', ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
|
||||||
|
SELECT * FROM public.check_database_privileges('grant_role2pc_user7', 'grant_role2pc_db', ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
|
||||||
|
|
||||||
|
\c grant_role2pc_db
|
||||||
|
|
||||||
|
grant grant_role2pc_user1 to grant_role2pc_user5,grant_role2pc_user6,grant_role2pc_user7;
|
||||||
|
|
||||||
|
\c regression
|
||||||
|
SELECT * FROM public.check_database_privileges('grant_role2pc_user5', 'grant_role2pc_db', ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
|
||||||
|
SELECT * FROM public.check_database_privileges('grant_role2pc_user6', 'grant_role2pc_db', ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
|
||||||
|
SELECT * FROM public.check_database_privileges('grant_role2pc_user7', 'grant_role2pc_db', ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
|
||||||
|
|
||||||
|
\c grant_role2pc_db
|
||||||
|
revoke grant_role2pc_user1 from grant_role2pc_user2;
|
||||||
|
|
||||||
|
--test revoke under transactional context with multiple operations
|
||||||
|
BEGIN;
|
||||||
|
revoke grant_role2pc_user1 from grant_role2pc_user3;
|
||||||
|
revoke grant_role2pc_user1 from grant_role2pc_user4;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
BEGIN;
|
||||||
|
revoke grant_role2pc_user1 from grant_role2pc_user5,grant_role2pc_user6;
|
||||||
|
revoke grant_role2pc_user1 from grant_role2pc_user7;
|
||||||
|
COMMIT;
|
||||||
|
|
||||||
|
\c regression
|
||||||
|
|
||||||
|
SELECT * FROM public.check_database_privileges('grant_role2pc_user2', 'grant_role2pc_db', ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
|
||||||
|
SELECT * FROM public.check_database_privileges('grant_role2pc_user3', 'grant_role2pc_db', ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
|
||||||
|
SELECT * FROM public.check_database_privileges('grant_role2pc_user4', 'grant_role2pc_db', ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
|
||||||
|
SELECT * FROM public.check_database_privileges('grant_role2pc_user5', 'grant_role2pc_db', ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
|
||||||
|
SELECT * FROM public.check_database_privileges('grant_role2pc_user6', 'grant_role2pc_db', ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
|
||||||
|
SELECT * FROM public.check_database_privileges('grant_role2pc_user7', 'grant_role2pc_db', ARRAY['CREATE', 'CONNECT', 'TEMP', 'TEMPORARY']);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
DROP SCHEMA grant_role2pc;
|
||||||
|
|
||||||
|
REVOKE ALL PRIVILEGES ON DATABASE grant_role2pc_db FROM grant_role2pc_user1;
|
||||||
|
DROP DATABASE grant_role2pc_db;
|
||||||
|
|
||||||
|
drop user grant_role2pc_user2,grant_role2pc_user3,grant_role2pc_user4,grant_role2pc_user5,grant_role2pc_user6,grant_role2pc_user7;
|
||||||
|
|
||||||
|
|
||||||
|
drop user grant_role2pc_user1;
|
||||||
|
|
||||||
|
grant connect,temp,temporary on database regression to public;
|
||||||
|
|
||||||
|
reset citus.enable_create_database_propagation;
|
|
@ -652,3 +652,16 @@ BEGIN
|
||||||
JOIN pg_dist_node USING (nodeid);
|
JOIN pg_dist_node USING (nodeid);
|
||||||
END;
|
END;
|
||||||
$func$ LANGUAGE plpgsql;
|
$func$ LANGUAGE plpgsql;
|
||||||
|
|
||||||
|
CREATE OR REPLACE FUNCTION check_database_privileges(role_name text, db_name text, permissions text[])
|
||||||
|
RETURNS TABLE(permission text, result text)
|
||||||
|
AS $func$
|
||||||
|
DECLARE
|
||||||
|
permission text;
|
||||||
|
BEGIN
|
||||||
|
FOREACH permission IN ARRAY permissions
|
||||||
|
LOOP
|
||||||
|
RETURN QUERY EXECUTE format($inner$SELECT '%s', result FROM run_command_on_all_nodes($$select has_database_privilege('%s','%s', '%s'); $$)$inner$, permission, role_name, db_name, permission);
|
||||||
|
END LOOP;
|
||||||
|
END;
|
||||||
|
$func$ LANGUAGE plpgsql;
|
||||||
|
|
Loading…
Reference in New Issue