</listitem>
</varlistentry>
+
<varlistentry id="app-psql-meta-command-drds">
<term><literal>\drds [ <link linkend="app-psql-patterns"><replaceable class="parameter">role-pattern</replaceable></link> [ <link linkend="app-psql-patterns"><replaceable class="parameter">database-pattern</replaceable></link> ] ]</literal></term>
<listitem>
</listitem>
</varlistentry>
+
+ <varlistentry id="app-psql-meta-command-drg">
+ <term><literal>\drg[S] [ <link linkend="app-psql-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
+ <listitem>
+ <para>
+ Lists information about each granted role membership, including
+ assigned options (<literal>ADMIN</literal>,
+ <literal>INHERIT</literal> and/or <literal>SET</literal>) and grantor.
+ See the <link linkend="sql-grant"><command>GRANT</command></link>
+ command for information about role memberships.
+ </para>
+ <para>
+ By default, only grants to user-created roles are shown; supply the
+ <literal>S</literal> modifier to include system roles.
+ If <replaceable class="parameter">pattern</replaceable> is specified,
+ only grants to those roles whose names match the pattern are listed.
+ </para>
+ </listitem>
+ </varlistentry>
+
+
<varlistentry id="app-psql-meta-command-drp">
<term><literal>\dRp[+] [ <link linkend="app-psql-patterns"><replaceable class="parameter">pattern</replaceable></link> ]</literal></term>
<listitem>
free(pattern2);
}
+ else if (cmd[2] == 'g')
+ success = describeRoleGrants(pattern, show_system);
else
status = PSQL_CMD_UNKNOWN;
break;
PGresult *res;
printTableContent cont;
printTableOpt myopt = pset.popt.topt;
- int ncols = 3;
+ int ncols = 2;
int nrows = 0;
int i;
int conns;
printfPQExpBuffer(&buf,
"SELECT r.rolname, r.rolsuper, r.rolinherit,\n"
" r.rolcreaterole, r.rolcreatedb, r.rolcanlogin,\n"
- " r.rolconnlimit, r.rolvaliduntil,\n"
- " ARRAY(SELECT b.rolname\n"
- " FROM pg_catalog.pg_auth_members m\n"
- " JOIN pg_catalog.pg_roles b ON (m.roleid = b.oid)\n"
- " WHERE m.member = r.oid) as memberof");
+ " r.rolconnlimit, r.rolvaliduntil");
if (verbose)
{
printTableAddHeader(&cont, gettext_noop("Role name"), true, align);
printTableAddHeader(&cont, gettext_noop("Attributes"), true, align);
- /* ignores implicit memberships from superuser & pg_database_owner */
- printTableAddHeader(&cont, gettext_noop("Member of"), true, align);
if (verbose)
printTableAddHeader(&cont, gettext_noop("Description"), true, align);
if (strcmp(PQgetvalue(res, i, 5), "t") != 0)
add_role_attribute(&buf, _("Cannot login"));
- if (strcmp(PQgetvalue(res, i, (verbose ? 10 : 9)), "t") == 0)
+ if (strcmp(PQgetvalue(res, i, (verbose ? 9 : 8)), "t") == 0)
add_role_attribute(&buf, _("Replication"));
if (pset.sversion >= 90500)
- if (strcmp(PQgetvalue(res, i, (verbose ? 11 : 10)), "t") == 0)
+ if (strcmp(PQgetvalue(res, i, (verbose ? 10 : 9)), "t") == 0)
add_role_attribute(&buf, _("Bypass RLS"));
conns = atoi(PQgetvalue(res, i, 6));
printTableAddCell(&cont, attr[i], false, false);
- printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
-
if (verbose)
- printTableAddCell(&cont, PQgetvalue(res, i, 9), false, false);
+ printTableAddCell(&cont, PQgetvalue(res, i, 8), false, false);
}
termPQExpBuffer(&buf);
return false;
}
+/*
+ * \drg
+ * Describes role grants.
+ */
+bool
+describeRoleGrants(const char *pattern, bool showSystem)
+{
+ PQExpBufferData buf;
+ PGresult *res;
+ printQueryOpt myopt = pset.popt;
+
+ initPQExpBuffer(&buf);
+ printfPQExpBuffer(&buf,
+ "SELECT m.rolname AS \"%s\", r.rolname AS \"%s\",\n"
+ " pg_catalog.concat_ws(', ',\n",
+ gettext_noop("Role name"),
+ gettext_noop("Member of"));
+
+ if (pset.sversion >= 160000)
+ appendPQExpBufferStr(&buf,
+ " CASE WHEN pam.admin_option THEN 'ADMIN' END,\n"
+ " CASE WHEN pam.inherit_option THEN 'INHERIT' END,\n"
+ " CASE WHEN pam.set_option THEN 'SET' END\n");
+ else
+ appendPQExpBufferStr(&buf,
+ " CASE WHEN pam.admin_option THEN 'ADMIN' END,\n"
+ " CASE WHEN m.rolinherit THEN 'INHERIT' END,\n"
+ " 'SET'\n");
+
+ appendPQExpBuffer(&buf,
+ " ) AS \"%s\",\n"
+ " g.rolname AS \"%s\"\n",
+ gettext_noop("Options"),
+ gettext_noop("Grantor"));
+
+ appendPQExpBufferStr(&buf,
+ "FROM pg_catalog.pg_roles m\n"
+ " JOIN pg_catalog.pg_auth_members pam ON (pam.member = m.oid)\n"
+ " LEFT JOIN pg_catalog.pg_roles r ON (pam.roleid = r.oid)\n"
+ " LEFT JOIN pg_catalog.pg_roles g ON (pam.grantor = g.oid)\n");
+
+ if (!showSystem && !pattern)
+ appendPQExpBufferStr(&buf, "WHERE m.rolname !~ '^pg_'\n");
+
+ if (!validateSQLNamePattern(&buf, pattern, false, false,
+ NULL, "m.rolname", NULL, NULL,
+ NULL, 1))
+ {
+ termPQExpBuffer(&buf);
+ return false;
+ }
+
+ appendPQExpBufferStr(&buf, "ORDER BY 1, 2, 4;\n");
+
+ res = PSQLexec(buf.data);
+ termPQExpBuffer(&buf);
+ if (!res)
+ return false;
+
+ myopt.nullPrint = NULL;
+ myopt.title = _("List of role grants");
+ myopt.translate_header = true;
+
+ printQuery(res, &myopt, pset.queryFout, false, pset.logfile);
+
+ PQclear(res);
+ return true;
+}
+
/*
* listTables()
/* \drds */
extern bool listDbRoleSettings(const char *pattern, const char *pattern2);
+/* \drg */
+extern bool describeRoleGrants(const char *pattern, bool showSystem);
+
/* \z (or \dp) */
extern bool permissionsList(const char *pattern, bool showSystem);
HELP0(" \\dp[S] [PATTERN] list table, view, and sequence access privileges\n");
HELP0(" \\dP[itn+] [PATTERN] list [only index/table] partitioned relations [n=nested]\n");
HELP0(" \\drds [ROLEPTRN [DBPTRN]] list per-database role settings\n");
+ HELP0(" \\drg[S] [PATTERN] list role grants\n");
HELP0(" \\dRp[+] [PATTERN] list replication publications\n");
HELP0(" \\dRs[+] [PATTERN] list replication subscriptions\n");
HELP0(" \\ds[S+] [PATTERN] list sequences\n");
"\\des", "\\det", "\\deu", "\\dew", "\\dE", "\\df",
"\\dF", "\\dFd", "\\dFp", "\\dFt", "\\dg", "\\di", "\\dl", "\\dL",
"\\dm", "\\dn", "\\do", "\\dO", "\\dp", "\\dP", "\\dPi", "\\dPt",
- "\\drds", "\\dRs", "\\dRp", "\\ds",
+ "\\drds", "\\drg", "\\dRs", "\\dRp", "\\ds",
"\\dt", "\\dT", "\\dv", "\\du", "\\dx", "\\dX", "\\dy",
"\\echo", "\\edit", "\\ef", "\\elif", "\\else", "\\encoding",
"\\endif", "\\errverbose", "\\ev",
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_tables);
else if (TailMatchesCS("\\dT*"))
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_datatypes);
- else if (TailMatchesCS("\\du*") || TailMatchesCS("\\dg*"))
+ else if (TailMatchesCS("\\du*") ||
+ TailMatchesCS("\\dg*") ||
+ TailMatchesCS("\\drg*"))
COMPLETE_WITH_QUERY(Query_for_list_of_roles);
else if (TailMatchesCS("\\dv*"))
COMPLETE_WITH_SCHEMA_QUERY(Query_for_list_of_views);
(0 rows)
\dg "no.such.role"
- List of roles
- Role name | Attributes | Member of
------------+------------+-----------
+ List of roles
+ Role name | Attributes
+-----------+------------
\dL "no.such.language"
List of languages
cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.data.type"
\dX "no.such.database"."no.such.schema"."no.such.extended.statistics"
cross-database references are not implemented: "no.such.database"."no.such.schema"."no.such.extended.statistics"
+-- check \drg and \du
+CREATE ROLE regress_du_role0;
+CREATE ROLE regress_du_role1;
+CREATE ROLE regress_du_role2;
+CREATE ROLE regress_du_admin;
+GRANT regress_du_role0 TO regress_du_admin WITH ADMIN TRUE;
+GRANT regress_du_role1 TO regress_du_admin WITH ADMIN TRUE;
+GRANT regress_du_role2 TO regress_du_admin WITH ADMIN TRUE;
+GRANT regress_du_role0 TO regress_du_role1 WITH ADMIN TRUE, INHERIT TRUE, SET TRUE GRANTED BY regress_du_admin;
+GRANT regress_du_role0 TO regress_du_role2 WITH ADMIN TRUE, INHERIT FALSE, SET FALSE GRANTED BY regress_du_admin;
+GRANT regress_du_role1 TO regress_du_role2 WITH ADMIN TRUE , INHERIT FALSE, SET TRUE GRANTED BY regress_du_admin;
+GRANT regress_du_role0 TO regress_du_role1 WITH ADMIN FALSE, INHERIT TRUE, SET FALSE GRANTED BY regress_du_role1;
+GRANT regress_du_role0 TO regress_du_role2 WITH ADMIN FALSE, INHERIT TRUE , SET TRUE GRANTED BY regress_du_role1;
+GRANT regress_du_role0 TO regress_du_role1 WITH ADMIN FALSE, INHERIT FALSE, SET TRUE GRANTED BY regress_du_role2;
+GRANT regress_du_role0 TO regress_du_role2 WITH ADMIN FALSE, INHERIT FALSE, SET FALSE GRANTED BY regress_du_role2;
+\drg regress_du_role*
+ List of role grants
+ Role name | Member of | Options | Grantor
+------------------+------------------+---------------------+------------------
+ regress_du_role1 | regress_du_role0 | ADMIN, INHERIT, SET | regress_du_admin
+ regress_du_role1 | regress_du_role0 | INHERIT | regress_du_role1
+ regress_du_role1 | regress_du_role0 | SET | regress_du_role2
+ regress_du_role2 | regress_du_role0 | ADMIN | regress_du_admin
+ regress_du_role2 | regress_du_role0 | INHERIT, SET | regress_du_role1
+ regress_du_role2 | regress_du_role0 | | regress_du_role2
+ regress_du_role2 | regress_du_role1 | ADMIN, SET | regress_du_admin
+(7 rows)
+
+\du regress_du_role*
+ List of roles
+ Role name | Attributes
+------------------+--------------
+ regress_du_role0 | Cannot login
+ regress_du_role1 | Cannot login
+ regress_du_role2 | Cannot login
+
+DROP ROLE regress_du_role0;
+DROP ROLE regress_du_role1;
+DROP ROLE regress_du_role2;
+DROP ROLE regress_du_admin;
\dP "no.such.database"."no.such.schema"."no.such.partitioned.relation"
\dT "no.such.database"."no.such.schema"."no.such.data.type"
\dX "no.such.database"."no.such.schema"."no.such.extended.statistics"
+
+-- check \drg and \du
+CREATE ROLE regress_du_role0;
+CREATE ROLE regress_du_role1;
+CREATE ROLE regress_du_role2;
+CREATE ROLE regress_du_admin;
+
+GRANT regress_du_role0 TO regress_du_admin WITH ADMIN TRUE;
+GRANT regress_du_role1 TO regress_du_admin WITH ADMIN TRUE;
+GRANT regress_du_role2 TO regress_du_admin WITH ADMIN TRUE;
+
+GRANT regress_du_role0 TO regress_du_role1 WITH ADMIN TRUE, INHERIT TRUE, SET TRUE GRANTED BY regress_du_admin;
+GRANT regress_du_role0 TO regress_du_role2 WITH ADMIN TRUE, INHERIT FALSE, SET FALSE GRANTED BY regress_du_admin;
+GRANT regress_du_role1 TO regress_du_role2 WITH ADMIN TRUE , INHERIT FALSE, SET TRUE GRANTED BY regress_du_admin;
+GRANT regress_du_role0 TO regress_du_role1 WITH ADMIN FALSE, INHERIT TRUE, SET FALSE GRANTED BY regress_du_role1;
+GRANT regress_du_role0 TO regress_du_role2 WITH ADMIN FALSE, INHERIT TRUE , SET TRUE GRANTED BY regress_du_role1;
+GRANT regress_du_role0 TO regress_du_role1 WITH ADMIN FALSE, INHERIT FALSE, SET TRUE GRANTED BY regress_du_role2;
+GRANT regress_du_role0 TO regress_du_role2 WITH ADMIN FALSE, INHERIT FALSE, SET FALSE GRANTED BY regress_du_role2;
+
+\drg regress_du_role*
+\du regress_du_role*
+
+DROP ROLE regress_du_role0;
+DROP ROLE regress_du_role1;
+DROP ROLE regress_du_role2;
+DROP ROLE regress_du_admin;