citus/src/backend/distributed/deparser/deparse_role_stmts.c

427 lines
9.9 KiB
C

/*-------------------------------------------------------------------------
*
* deparse_role_stmts.c
* All routines to deparse role statements.
* This file contains all entry points specific for ALTER ROLE statement
* deparsing as well as functions that are currently only used for deparsing
* ALTER ROLE statements.
*
* Copyright (c), Citus Data, Inc.
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "distributed/citus_ruleutils.h"
#include "distributed/deparser.h"
#include "lib/stringinfo.h"
#include "nodes/parsenodes.h"
#include "utils/builtins.h"
static void AppendAlterRoleStmt(StringInfo buf, AlterRoleStmt *stmt);
static void AppendAlterRoleSetStmt(StringInfo buf, AlterRoleSetStmt *stmt);
static void AppendCreateRoleStmt(StringInfo buf, CreateRoleStmt *stmt);
static void AppendRoleOption(StringInfo buf, ListCell *optionCell);
static void AppendRoleList(StringInfo buf, List *roleList);
static void AppendDropRoleStmt(StringInfo buf, DropRoleStmt *stmt);
static void AppendGrantRoleStmt(StringInfo buf, GrantRoleStmt *stmt);
/*
* DeparseAlterRoleStmt builds and returns a string representing of the
* AlterRoleStmt for application on a remote server.
*/
char *
DeparseAlterRoleStmt(Node *node)
{
AlterRoleStmt *stmt = castNode(AlterRoleStmt, node);
StringInfoData buf = { 0 };
initStringInfo(&buf);
AppendAlterRoleStmt(&buf, stmt);
return buf.data;
}
/*
* DeparseAlterRoleSetStmt builds and returns a string representing of the
* AlterRoleSetStmt for application on a remote server.
*/
char *
DeparseAlterRoleSetStmt(Node *node)
{
AlterRoleSetStmt *stmt = castNode(AlterRoleSetStmt, node);
StringInfoData buf = { 0 };
initStringInfo(&buf);
AppendAlterRoleSetStmt(&buf, stmt);
return buf.data;
}
/*
* AppendAlterRoleStmt generates the string representation of the
* AlterRoleStmt and appends it to the buffer.
*/
static void
AppendAlterRoleStmt(StringInfo buf, AlterRoleStmt *stmt)
{
ListCell *optionCell = NULL;
RoleSpec *role = stmt->role;
/*
* If the role_specification used is CURRENT_USER or SESSION_USER,
* it will be converted to thats roles role name.
*/
appendStringInfo(buf, "ALTER ROLE %s", RoleSpecString(role, true));
foreach(optionCell, stmt->options)
{
AppendRoleOption(buf, optionCell);
}
}
/*
* AppendRoleOption generates the string representation for the role options
* and appends it to the buffer.
*
* This function only generates strings for common role options of ALTER ROLE
* and CREATE ROLE statements. The extra options for CREATE ROLE are handled
* seperately.
*/
static void
AppendRoleOption(StringInfo buf, ListCell *optionCell)
{
DefElem *option = (DefElem *) lfirst(optionCell);
if (strcmp(option->defname, "superuser") == 0 && intVal(option->arg))
{
appendStringInfo(buf, " SUPERUSER");
}
else if (strcmp(option->defname, "superuser") == 0 && !intVal(option->arg))
{
appendStringInfo(buf, " NOSUPERUSER");
}
else if (strcmp(option->defname, "createdb") == 0 && intVal(option->arg))
{
appendStringInfo(buf, " CREATEDB");
}
else if (strcmp(option->defname, "createdb") == 0 && !intVal(option->arg))
{
appendStringInfo(buf, " NOCREATEDB");
}
else if (strcmp(option->defname, "createrole") == 0 && intVal(option->arg))
{
appendStringInfo(buf, " CREATEROLE");
}
else if (strcmp(option->defname, "createrole") == 0 && !intVal(option->arg))
{
appendStringInfo(buf, " NOCREATEROLE");
}
else if (strcmp(option->defname, "inherit") == 0 && intVal(option->arg))
{
appendStringInfo(buf, " INHERIT");
}
else if (strcmp(option->defname, "inherit") == 0 && !intVal(option->arg))
{
appendStringInfo(buf, " NOINHERIT");
}
else if (strcmp(option->defname, "canlogin") == 0 && intVal(option->arg))
{
appendStringInfo(buf, " LOGIN");
}
else if (strcmp(option->defname, "canlogin") == 0 && !intVal(option->arg))
{
appendStringInfo(buf, " NOLOGIN");
}
else if (strcmp(option->defname, "isreplication") == 0 && intVal(option->arg))
{
appendStringInfo(buf, " REPLICATION");
}
else if (strcmp(option->defname, "isreplication") == 0 && !intVal(option->arg))
{
appendStringInfo(buf, " NOREPLICATION");
}
else if (strcmp(option->defname, "bypassrls") == 0 && intVal(option->arg))
{
appendStringInfo(buf, " BYPASSRLS");
}
else if (strcmp(option->defname, "bypassrls") == 0 && !intVal(option->arg))
{
appendStringInfo(buf, " NOBYPASSRLS");
}
else if (strcmp(option->defname, "connectionlimit") == 0)
{
appendStringInfo(buf, " CONNECTION LIMIT %d", intVal(option->arg));
}
else if (strcmp(option->defname, "password") == 0)
{
if (option->arg != NULL)
{
appendStringInfo(buf, " PASSWORD %s", quote_literal_cstr(strVal(
option->arg)));
}
else
{
appendStringInfo(buf, " PASSWORD NULL");
}
}
else if (strcmp(option->defname, "validUntil") == 0)
{
appendStringInfo(buf, " VALID UNTIL %s", quote_literal_cstr(strVal(option->arg)));
}
}
/*
* DeparseCreateRoleStmt builds and returns a string representing of the
* CreateRoleStmt for application on a remote server.
*/
char *
DeparseCreateRoleStmt(Node *node)
{
CreateRoleStmt *stmt = castNode(CreateRoleStmt, node);
StringInfoData buf = { 0 };
initStringInfo(&buf);
AppendCreateRoleStmt(&buf, stmt);
return buf.data;
}
/*
* AppendCreateRoleStmt generates the string representation of the
* CreateRoleStmt and appends it to the buffer.
*/
static void
AppendCreateRoleStmt(StringInfo buf, CreateRoleStmt *stmt)
{
ListCell *optionCell = NULL;
appendStringInfo(buf, "CREATE ");
switch (stmt->stmt_type)
{
case ROLESTMT_ROLE:
{
appendStringInfo(buf, "ROLE ");
break;
}
case ROLESTMT_USER:
{
appendStringInfo(buf, "USER ");
break;
}
case ROLESTMT_GROUP:
{
appendStringInfo(buf, "GROUP ");
break;
}
}
appendStringInfo(buf, "%s", quote_identifier(stmt->role));
foreach(optionCell, stmt->options)
{
AppendRoleOption(buf, optionCell);
DefElem *option = (DefElem *) lfirst(optionCell);
if (strcmp(option->defname, "sysid") == 0)
{
appendStringInfo(buf, " SYSID %s", quote_literal_cstr(strVal(option->arg)));
}
else if (strcmp(option->defname, "adminmembers") == 0)
{
appendStringInfo(buf, " ADMIN ");
AppendRoleList(buf, (List *) option->arg);
}
else if (strcmp(option->defname, "rolemembers") == 0)
{
appendStringInfo(buf, " ROLE ");
AppendRoleList(buf, (List *) option->arg);
}
else if (strcmp(option->defname, "addroleto") == 0)
{
appendStringInfo(buf, " IN ROLE ");
AppendRoleList(buf, (List *) option->arg);
}
}
}
/*
* DeparseDropRoleStmt builds and returns a string representing of the
* DropRoleStmt for application on a remote server.
*/
char *
DeparseDropRoleStmt(Node *node)
{
DropRoleStmt *stmt = castNode(DropRoleStmt, node);
StringInfoData buf = { 0 };
initStringInfo(&buf);
AppendDropRoleStmt(&buf, stmt);
return buf.data;
}
/*
* AppendDropRoleStmt generates the string representation of the
* DropRoleStmt and appends it to the buffer.
*/
static void
AppendDropRoleStmt(StringInfo buf, DropRoleStmt *stmt)
{
appendStringInfo(buf, "DROP ROLE ");
if (stmt->missing_ok)
{
appendStringInfo(buf, "IF EXISTS ");
}
AppendRoleList(buf, stmt->roles);
}
static void
AppendRoleList(StringInfo buf, List *roleList)
{
ListCell *cell = NULL;
foreach(cell, roleList)
{
Node *roleNode = (Node *) lfirst(cell);
Assert(IsA(roleNode, RoleSpec) || IsA(roleNode, AccessPriv));
char const *rolename = NULL;
if (IsA(roleNode, RoleSpec))
{
rolename = RoleSpecString((RoleSpec *) roleNode, true);
}
if (IsA(roleNode, AccessPriv))
{
rolename = quote_identifier(((AccessPriv *) roleNode)->priv_name);
}
appendStringInfoString(buf, rolename);
if (cell != list_tail(roleList))
{
appendStringInfo(buf, ", ");
}
}
}
/*
* DeparseGrantRoleStmt builds and returns a string representing of the
* GrantRoleStmt for application on a remote server.
*/
char *
DeparseGrantRoleStmt(Node *node)
{
GrantRoleStmt *stmt = castNode(GrantRoleStmt, node);
StringInfoData buf = { 0 };
initStringInfo(&buf);
AppendGrantRoleStmt(&buf, stmt);
return buf.data;
}
/*
* AppendGrantRoleStmt generates the string representation of the
* GrantRoleStmt and appends it to the buffer.
*/
static void
AppendGrantRoleStmt(StringInfo buf, GrantRoleStmt *stmt)
{
appendStringInfo(buf, "%s ", stmt->is_grant ? "GRANT" : "REVOKE");
if (!stmt->is_grant && stmt->admin_opt)
{
appendStringInfo(buf, "ADMIN OPTION FOR ");
}
AppendRoleList(buf, stmt->granted_roles);
appendStringInfo(buf, "%s ", stmt->is_grant ? " TO " : " FROM ");
AppendRoleList(buf, stmt->grantee_roles);
if (stmt->is_grant)
{
if (stmt->admin_opt)
{
appendStringInfo(buf, " WITH ADMIN OPTION");
}
if (stmt->grantor)
{
appendStringInfo(buf, " GRANTED BY %s", RoleSpecString(stmt->grantor, true));
}
}
else
{
if (stmt->behavior == DROP_RESTRICT)
{
appendStringInfo(buf, " RESTRICT");
}
else if (stmt->behavior == DROP_CASCADE)
{
appendStringInfo(buf, " CASCADE");
}
}
}
/*
* AppendAlterRoleSetStmt generates the string representation of the
* AlterRoleSetStmt and appends it to the buffer.
*/
static void
AppendAlterRoleSetStmt(StringInfo buf, AlterRoleSetStmt *stmt)
{
RoleSpec *role = stmt->role;
const char *roleSpecStr = NULL;
if (role == NULL)
{
/*
* If all roles are be affected, role field is left blank in an
* AlterRoleSetStmt.
*/
roleSpecStr = "ALL";
}
else
{
/*
* If the role_specification used is CURRENT_USER or SESSION_USER,
* it will be converted to thats roles role name.
*
* We also set withQuoteIdentifier parameter to true. Since the
* roleSpecStr will be used in a query, the quotes are needed.
*/
roleSpecStr = RoleSpecString(role, true);
}
appendStringInfo(buf, "ALTER ROLE %s", roleSpecStr);
if (stmt->database != NULL)
{
appendStringInfo(buf, " IN DATABASE %s", quote_identifier(stmt->database));
}
VariableSetStmt *setStmt = castNode(VariableSetStmt, stmt->setstmt);
AppendVariableSet(buf, setStmt);
}