/*------------------------------------------------------------------------- * * 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); }