Skip to content

Commit 60684dd

Browse files
committed
Add grantable MAINTAIN privilege and pg_maintain role.
Allows VACUUM, ANALYZE, REINDEX, REFRESH MATERIALIZED VIEW, CLUSTER, and LOCK TABLE. Effectively reverts 4441fc7. Instead of creating separate privileges for VACUUM, ANALYZE, and other maintenance commands, group them together under a single MAINTAIN privilege. Author: Nathan Bossart Discussion: https://postgr.es/m/20221212210136.GA449764@nathanxps13 Discussion: https://postgr.es/m/[email protected]
1 parent c6f6646 commit 60684dd

36 files changed

+340
-354
lines changed

‎doc/src/sgml/ddl.sgml

+15-27
Original file line numberDiff line numberDiff line change
@@ -1692,8 +1692,7 @@ ALTER TABLE products RENAME TO items;
16921692
<literal>TRUNCATE</literal>, <literal>REFERENCES</literal>, <literal>TRIGGER</literal>,
16931693
<literal>CREATE</literal>, <literal>CONNECT</literal>, <literal>TEMPORARY</literal>,
16941694
<literal>EXECUTE</literal>, <literal>USAGE</literal>, <literal>SET</literal>,
1695-
<literal>ALTER SYSTEM</literal>, <literal>VACUUM</literal>, and
1696-
<literal>ANALYZE</literal>.
1695+
<literal>ALTER SYSTEM</literal>, and <literal>MAINTAIN</literal>.
16971696
The privileges applicable to a particular
16981697
object vary depending on the object's type (table, function, etc.).
16991698
More detail about the meanings of these privileges appears below.
@@ -1985,19 +1984,13 @@ REVOKE ALL ON accounts FROM PUBLIC;
19851984
</varlistentry>
19861985

19871986
<varlistentry>
1988-
<term><literal>VACUUM</literal></term>
1987+
<term><literal>MAINTAIN</literal></term>
19891988
<listitem>
19901989
<para>
1991-
Allows <command>VACUUM</command> on a relation.
1992-
</para>
1993-
</listitem>
1994-
</varlistentry>
1995-
1996-
<varlistentry>
1997-
<term><literal>ANALYZE</literal></term>
1998-
<listitem>
1999-
<para>
2000-
Allows <command>ANALYZE</command> on a relation.
1990+
Allows <command>VACUUM</command>, <command>ANALYZE</command>,
1991+
<command>CLUSTER</command>, <command>REFRESH MATERIALIZED VIEW</command>,
1992+
<command>REINDEX</command>, and <command>LOCK TABLE</command> on a
1993+
relation.
20011994
</para>
20021995
</listitem>
20031996
</varlistentry>
@@ -2151,13 +2144,8 @@ REVOKE ALL ON accounts FROM PUBLIC;
21512144
<entry><literal>PARAMETER</literal></entry>
21522145
</row>
21532146
<row>
2154-
<entry><literal>VACUUM</literal></entry>
2155-
<entry><literal>v</literal></entry>
2156-
<entry><literal>TABLE</literal></entry>
2157-
</row>
2158-
<row>
2159-
<entry><literal>ANALYZE</literal></entry>
2160-
<entry><literal>z</literal></entry>
2147+
<entry><literal>MAINTAIN</literal></entry>
2148+
<entry><literal>m</literal></entry>
21612149
<entry><literal>TABLE</literal></entry>
21622150
</row>
21632151
</tbody>
@@ -2250,7 +2238,7 @@ REVOKE ALL ON accounts FROM PUBLIC;
22502238
</row>
22512239
<row>
22522240
<entry><literal>TABLE</literal> (and table-like objects)</entry>
2253-
<entry><literal>arwdDxtvz</literal></entry>
2241+
<entry><literal>arwdDxtm</literal></entry>
22542242
<entry>none</entry>
22552243
<entry><literal>\dp</literal></entry>
22562244
</row>
@@ -2308,12 +2296,12 @@ GRANT SELECT (col1), UPDATE (col1) ON mytable TO miriam_rw;
23082296
would show:
23092297
<programlisting>
23102298
=&gt; \dp mytable
2311-
Access privileges
2312-
Schema | Name | Type | Access privileges | Column privileges | Policies
2313-
--------+---------+-------+-------------------------+-----------------------+----------
2314-
public | mytable | table | miriam=arwdDxtvz/miriam+| col1: +|
2315-
| | | =r/miriam +| miriam_rw=rw/miriam |
2316-
| | | admin=arw/miriam | |
2299+
Access privileges
2300+
Schema | Name | Type | Access privileges | Column privileges | Policies
2301+
--------+---------+-------+------------------------+-----------------------+----------
2302+
public | mytable | table | miriam=arwdDxtm/miriam+| col1: +|
2303+
| | | =r/miriam +| miriam_rw=rw/miriam |
2304+
| | | admin=arw/miriam | |
23172305
(1 row)
23182306
</programlisting>
23192307
</para>

‎doc/src/sgml/func.sgml

+1-2
Original file line numberDiff line numberDiff line change
@@ -22995,8 +22995,7 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute');
2299522995
are <literal>SELECT</literal>, <literal>INSERT</literal>,
2299622996
<literal>UPDATE</literal>, <literal>DELETE</literal>,
2299722997
<literal>TRUNCATE</literal>, <literal>REFERENCES</literal>,
22998-
<literal>TRIGGER</literal>, <literal>VACUUM</literal> and
22999-
<literal>ANALYZE</literal>.
22998+
<literal>TRIGGER</literal>, and <literal>MAINTAIN</literal>.
2300022999
</para></entry>
2300123000
</row>
2300223001

‎doc/src/sgml/ref/alter_default_privileges.sgml

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ ALTER DEFAULT PRIVILEGES
2828

2929
<phrase>where <replaceable class="parameter">abbreviated_grant_or_revoke</replaceable> is one of:</phrase>
3030

31-
GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | VACUUM | ANALYZE }
31+
GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | MAINTAIN }
3232
[, ...] | ALL [ PRIVILEGES ] }
3333
ON TABLES
3434
TO { [ GROUP ] <replaceable class="parameter">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
@@ -51,7 +51,7 @@ GRANT { USAGE | CREATE | ALL [ PRIVILEGES ] }
5151
TO { [ GROUP ] <replaceable class="parameter">role_name</replaceable> | PUBLIC } [, ...] [ WITH GRANT OPTION ]
5252

5353
REVOKE [ GRANT OPTION FOR ]
54-
{ { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | VACUUM | ANALYZE }
54+
{ { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | MAINTAIN }
5555
[, ...] | ALL [ PRIVILEGES ] }
5656
ON TABLES
5757
FROM { [ GROUP ] <replaceable class="parameter">role_name</replaceable> | PUBLIC } [, ...]

‎doc/src/sgml/ref/analyze.sgml

+4-5
Original file line numberDiff line numberDiff line change
@@ -148,16 +148,15 @@ ANALYZE [ VERBOSE ] [ <replaceable class="parameter">table_and_columns</replacea
148148
<title>Notes</title>
149149

150150
<para>
151-
To analyze a table, one must ordinarily have the <literal>ANALYZE</literal>
151+
To analyze a table, one must ordinarily have the <literal>MAINTAIN</literal>
152152
privilege on the table or be the table's owner, a superuser, or a role with
153153
privileges of the
154-
<link linkend="predefined-roles-table"><literal>pg_analyze_all_tables</literal></link>
155-
role.
156-
However, database owners are allowed to
154+
<link linkend="predefined-roles-table"><literal>pg_maintain</literal></link>
155+
role. However, database owners are allowed to
157156
analyze all tables in their databases, except shared catalogs.
158157
(The restriction for shared catalogs means that a true database-wide
159158
<command>ANALYZE</command> can only be performed by superusers and roles
160-
with privileges of <literal>pg_analyze_all_tables</literal>.)
159+
with privileges of <literal>pg_maintain</literal>.)
161160
<command>ANALYZE</command> will skip over any tables that the calling user
162161
does not have permission to analyze.
163162
</para>

‎doc/src/sgml/ref/cluster.sgml

+5-3
Original file line numberDiff line numberDiff line change
@@ -69,9 +69,11 @@ CLUSTER [VERBOSE]
6969
<para>
7070
<command>CLUSTER</command> without any parameter reclusters all the
7171
previously-clustered tables in the current database that the calling user
72-
owns, or all such tables if called by a superuser. This
73-
form of <command>CLUSTER</command> cannot be executed inside a transaction
74-
block.
72+
owns or has the <literal>MAINTAIN</literal> privilege for, or all such tables
73+
if called by a superuser or a role with privileges of the
74+
<link linkend="predefined-roles-table"><literal>pg_maintain</literal></link>
75+
role. This form of <command>CLUSTER</command> cannot be
76+
executed inside a transaction block.
7577
</para>
7678

7779
<para>

‎doc/src/sgml/ref/grant.sgml

+2-3
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ PostgreSQL documentation
2121

2222
<refsynopsisdiv>
2323
<synopsis>
24-
GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | VACUUM | ANALYZE }
24+
GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | MAINTAIN }
2525
[, ...] | ALL [ PRIVILEGES ] }
2626
ON { [ TABLE ] <replaceable class="parameter">table_name</replaceable> [, ...]
2727
| ALL TABLES IN SCHEMA <replaceable class="parameter">schema_name</replaceable> [, ...] }
@@ -193,8 +193,7 @@ GRANT <replaceable class="parameter">role_name</replaceable> [, ...] TO <replace
193193
<term><literal>USAGE</literal></term>
194194
<term><literal>SET</literal></term>
195195
<term><literal>ALTER SYSTEM</literal></term>
196-
<term><literal>VACUUM</literal></term>
197-
<term><literal>ANALYZE</literal></term>
196+
<term><literal>MAINTAIN</literal></term>
198197
<listitem>
199198
<para>
200199
Specific types of privileges, as defined in <xref linkend="ddl-priv"/>.

‎doc/src/sgml/ref/lock.sgml

+11-5
Original file line numberDiff line numberDiff line change
@@ -165,11 +165,17 @@ LOCK [ TABLE ] [ ONLY ] <replaceable class="parameter">name</replaceable> [ * ]
165165
<title>Notes</title>
166166

167167
<para>
168-
<literal>LOCK TABLE ... IN ACCESS SHARE MODE</literal> requires <literal>SELECT</literal>
169-
privileges on the target table. <literal>LOCK TABLE ... IN ROW EXCLUSIVE
170-
MODE</literal> requires <literal>INSERT</literal>, <literal>UPDATE</literal>, <literal>DELETE</literal>,
171-
or <literal>TRUNCATE</literal> privileges on the target table. All other forms of
172-
<command>LOCK</command> require table-level <literal>UPDATE</literal>, <literal>DELETE</literal>,
168+
To lock a table, one must ordinarily have the <literal>MAINTAIN</literal>
169+
privilege on the table or be the table's owner, a superuser, or a role
170+
with privileges of the
171+
<link linkend="predefined-roles-table"><literal>pg_maintain</literal></link>
172+
role. <literal>LOCK TABLE ... IN ACCESS SHARE MODE</literal> is allowed
173+
with <literal>SELECT</literal> privileges on the target
174+
table. <literal>LOCK TABLE ... IN ROW EXCLUSIVE MODE</literal> is allowed
175+
with <literal>INSERT</literal>, <literal>UPDATE</literal>, <literal>DELETE</literal>,
176+
or <literal>TRUNCATE</literal> privileges on the target table. All other
177+
forms of <command>LOCK</command> are allowed with
178+
table-level <literal>UPDATE</literal>, <literal>DELETE</literal>,
173179
or <literal>TRUNCATE</literal> privileges.
174180
</para>
175181

‎doc/src/sgml/ref/refresh_materialized_view.sgml

+4-1
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,10 @@ REFRESH MATERIALIZED VIEW [ CONCURRENTLY ] <replaceable class="parameter">name</
3232
<para>
3333
<command>REFRESH MATERIALIZED VIEW</command> completely replaces the
3434
contents of a materialized view. To execute this command you must be the
35-
owner of the materialized view. The old contents are discarded. If
35+
owner of the materialized view, have privileges of the
36+
<link linkend="predefined-roles-table"><literal>pg_maintain</literal></link>
37+
role, or have the <literal>MAINTAIN</literal>
38+
privilege on the materialized view. The old contents are discarded. If
3639
<literal>WITH DATA</literal> is specified (or defaults) the backing query
3740
is executed to provide the new data, and the materialized view is left in a
3841
scannable state. If <literal>WITH NO DATA</literal> is specified no new

‎doc/src/sgml/ref/reindex.sgml

+9-4
Original file line numberDiff line numberDiff line change
@@ -293,15 +293,20 @@ REINDEX [ ( <replaceable class="parameter">option</replaceable> [, ...] ) ] { DA
293293

294294
<para>
295295
Reindexing a single index or table requires being the owner of that
296-
index or table. Reindexing a schema or database requires being the
297-
owner of that schema or database. Note specifically that it's thus
296+
index or table, having privileges of the
297+
<link linkend="predefined-roles-table"><literal>pg_maintain</literal></link>
298+
role, or having the <literal>MAINTAIN</literal> privilege on the
299+
table. Reindexing a schema or database requires being the
300+
owner of that schema or database or having privileges of the
301+
<literal>pg_maintain</literal> role. Note specifically that it's thus
298302
possible for non-superusers to rebuild indexes of tables owned by
299303
other users. However, as a special exception, when
300304
<command>REINDEX DATABASE</command>, <command>REINDEX SCHEMA</command>
301305
or <command>REINDEX SYSTEM</command> is issued by a non-superuser,
302306
indexes on shared catalogs will be skipped unless the user owns the
303-
catalog (which typically won't be the case). Of course, superusers
304-
can always reindex anything.
307+
catalog (which typically won't be the case), has privileges of the
308+
<literal>pg_maintain</literal> role, or has the <literal>MAINTAIN</literal>
309+
privilege on the catalog. Of course, superusers can always reindex anything.
305310
</para>
306311

307312
<para>

‎doc/src/sgml/ref/revoke.sgml

+1-1
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ PostgreSQL documentation
2222
<refsynopsisdiv>
2323
<synopsis>
2424
REVOKE [ GRANT OPTION FOR ]
25-
{ { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | VACUUM | ANALYZE }
25+
{ { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | MAINTAIN }
2626
[, ...] | ALL [ PRIVILEGES ] }
2727
ON { [ TABLE ] <replaceable class="parameter">table_name</replaceable> [, ...]
2828
| ALL TABLES IN SCHEMA <replaceable>schema_name</replaceable> [, ...] }

‎doc/src/sgml/ref/vacuum.sgml

+4-5
Original file line numberDiff line numberDiff line change
@@ -356,16 +356,15 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ <replaceable class="paramet
356356
<title>Notes</title>
357357

358358
<para>
359-
To vacuum a table, one must ordinarily have the <literal>VACUUM</literal>
359+
To vacuum a table, one must ordinarily have the <literal>MAINTAIN</literal>
360360
privilege on the table or be the table's owner, a superuser, or a role with
361361
privileges of the
362-
<link linkend="predefined-roles-table"><literal>pg_vacuum_all_tables</literal></link>
363-
role.
364-
However, database owners are allowed to
362+
<link linkend="predefined-roles-table"><literal>pg_maintain</literal></link>
363+
role. However, database owners are allowed to
365364
vacuum all tables in their databases, except shared catalogs.
366365
(The restriction for shared catalogs means that a true database-wide
367366
<command>VACUUM</command> can only be performed by superusers and roles
368-
with privileges of <literal>pg_vacuum_all_tables</literal>.)
367+
with privileges of <literal>pg_maintain</literal>.)
369368
<command>VACUUM</command> will skip over any tables that the calling user
370369
does not have permission to vacuum.
371370
</para>

‎doc/src/sgml/user-manag.sgml

+9-10
Original file line numberDiff line numberDiff line change
@@ -636,16 +636,15 @@ DROP ROLE doomed_role;
636636
command.</entry>
637637
</row>
638638
<row>
639-
<entry>pg_vacuum_all_tables</entry>
640-
<entry>Allow executing the
641-
<link linkend="sql-vacuum"><command>VACUUM</command></link> command on
642-
all tables.</entry>
643-
</row>
644-
<row>
645-
<entry>pg_analyze_all_tables</entry>
646-
<entry>Allow executing the
647-
<link linkend="sql-analyze"><command>ANALYZE</command></link> command on
648-
all tables.</entry>
639+
<entry>pg_maintain</entry>
640+
<entry>Allow executing
641+
<link linkend="sql-vacuum"><command>VACUUM</command></link>,
642+
<link linkend="sql-analyze"><command>ANALYZE</command></link>,
643+
<link linkend="sql-cluster"><command>CLUSTER</command></link>,
644+
<link linkend="sql-refreshmaterializedview"><command>REFRESH MATERIALIZED VIEW</command></link>,
645+
<link linkend="sql-reindex"><command>REINDEX</command></link>,
646+
and <link linkend="sql-lock"><command>LOCK TABLE</command></link> on all
647+
relations.</entry>
649648
</row>
650649
</tbody>
651650
</tgroup>

‎src/backend/catalog/aclchk.c

+11-24
Original file line numberDiff line numberDiff line change
@@ -2618,10 +2618,8 @@ string_to_privilege(const char *privname)
26182618
return ACL_SET;
26192619
if (strcmp(privname, "alter system") == 0)
26202620
return ACL_ALTER_SYSTEM;
2621-
if (strcmp(privname, "vacuum") == 0)
2622-
return ACL_VACUUM;
2623-
if (strcmp(privname, "analyze") == 0)
2624-
return ACL_ANALYZE;
2621+
if (strcmp(privname, "maintain") == 0)
2622+
return ACL_MAINTAIN;
26252623
if (strcmp(privname, "rule") == 0)
26262624
return 0; /* ignore old RULE privileges */
26272625
ereport(ERROR,
@@ -2663,10 +2661,8 @@ privilege_to_string(AclMode privilege)
26632661
return "SET";
26642662
case ACL_ALTER_SYSTEM:
26652663
return "ALTER SYSTEM";
2666-
case ACL_VACUUM:
2667-
return "VACUUM";
2668-
case ACL_ANALYZE:
2669-
return "ANALYZE";
2664+
case ACL_MAINTAIN:
2665+
return "MAINTAIN";
26702666
default:
26712667
elog(ERROR, "unrecognized privilege: %d", (int) privilege);
26722668
}
@@ -3401,24 +3397,15 @@ pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask,
34013397
result |= (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE));
34023398

34033399
/*
3404-
* Check if ACL_VACUUM is being checked and, if so, and not already set as
3400+
* Check if ACL_MAINTAIN is being checked and, if so, and not already set as
34053401
* part of the result, then check if the user is a member of the
3406-
* pg_vacuum_all_tables role, which allows VACUUM on all relations.
3402+
* pg_maintain role, which allows VACUUM, ANALYZE, CLUSTER, REFRESH
3403+
* MATERIALIZED VIEW, and REINDEX on all relations.
34073404
*/
3408-
if (mask & ACL_VACUUM &&
3409-
!(result & ACL_VACUUM) &&
3410-
has_privs_of_role(roleid, ROLE_PG_VACUUM_ALL_TABLES))
3411-
result |= ACL_VACUUM;
3412-
3413-
/*
3414-
* Check if ACL_ANALYZE is being checked and, if so, and not already set as
3415-
* part of the result, then check if the user is a member of the
3416-
* pg_analyze_all_tables role, which allows ANALYZE on all relations.
3417-
*/
3418-
if (mask & ACL_ANALYZE &&
3419-
!(result & ACL_ANALYZE) &&
3420-
has_privs_of_role(roleid, ROLE_PG_ANALYZE_ALL_TABLES))
3421-
result |= ACL_ANALYZE;
3405+
if (mask & ACL_MAINTAIN &&
3406+
!(result & ACL_MAINTAIN) &&
3407+
has_privs_of_role(roleid, ROLE_PG_MAINTAIN))
3408+
result |= ACL_MAINTAIN;
34223409

34233410
return result;
34243411
}

‎src/backend/commands/analyze.c

+1-1
Original file line numberDiff line numberDiff line change
@@ -167,7 +167,7 @@ analyze_rel(Oid relid, RangeVar *relation,
167167
*/
168168
if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
169169
onerel->rd_rel,
170-
VACOPT_ANALYZE))
170+
params->options & VACOPT_ANALYZE))
171171
{
172172
relation_close(onerel, ShareUpdateExclusiveLock);
173173
return;

0 commit comments

Comments
 (0)