Skip to content

Navigation Menu

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit b5d6382

Browse filesBrowse files
committed
Provide per-table permissions for vacuum and analyze.
Currently a table can only be vacuumed or analyzed by its owner or a superuser. This can now be extended to any user by means of an appropriate GRANT. Nathan Bossart Reviewed by: Bharath Rupireddy, Kyotaro Horiguchi, Stephen Frost, Robert Haas, Mark Dilger, Tom Lane, Corey Huinker, David G. Johnston, Michael Paquier. Discussion: https://postgr.es/m/20220722203735.GB3996698@nathanxps13
1 parent 1f059a4 commit b5d6382
Copy full SHA for b5d6382

24 files changed

+274
-113
lines changed

‎doc/src/sgml/ddl.sgml

Copy file name to clipboardExpand all lines: doc/src/sgml/ddl.sgml
+39-10Lines changed: 39 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1691,8 +1691,9 @@ ALTER TABLE products RENAME TO items;
16911691
<literal>INSERT</literal>, <literal>UPDATE</literal>, <literal>DELETE</literal>,
16921692
<literal>TRUNCATE</literal>, <literal>REFERENCES</literal>, <literal>TRIGGER</literal>,
16931693
<literal>CREATE</literal>, <literal>CONNECT</literal>, <literal>TEMPORARY</literal>,
1694-
<literal>EXECUTE</literal>, <literal>USAGE</literal>, <literal>SET</literal>
1695-
and <literal>ALTER SYSTEM</literal>.
1694+
<literal>EXECUTE</literal>, <literal>USAGE</literal>, <literal>SET</literal>,
1695+
<literal>ALTER SYSTEM</literal>, <literal>VACUUM</literal>, and
1696+
<literal>ANALYZE</literal>.
16961697
The privileges applicable to a particular
16971698
object vary depending on the object's type (table, function, etc.).
16981699
More detail about the meanings of these privileges appears below.
@@ -1982,7 +1983,25 @@ REVOKE ALL ON accounts FROM PUBLIC;
19821983
</para>
19831984
</listitem>
19841985
</varlistentry>
1985-
</variablelist>
1986+
1987+
<varlistentry>
1988+
<term><literal>VACUUM</literal></term>
1989+
<listitem>
1990+
<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.
2001+
</para>
2002+
</listitem>
2003+
</varlistentry>
2004+
</variablelist>
19862005

19872006
The privileges required by other commands are listed on the
19882007
reference page of the respective command.
@@ -2131,6 +2150,16 @@ REVOKE ALL ON accounts FROM PUBLIC;
21312150
<entry><literal>A</literal></entry>
21322151
<entry><literal>PARAMETER</literal></entry>
21332152
</row>
2153+
<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>
2161+
<entry><literal>TABLE</literal></entry>
2162+
</row>
21342163
</tbody>
21352164
</tgroup>
21362165
</table>
@@ -2221,7 +2250,7 @@ REVOKE ALL ON accounts FROM PUBLIC;
22212250
</row>
22222251
<row>
22232252
<entry><literal>TABLE</literal> (and table-like objects)</entry>
2224-
<entry><literal>arwdDxt</literal></entry>
2253+
<entry><literal>arwdDxtvz</literal></entry>
22252254
<entry>none</entry>
22262255
<entry><literal>\dp</literal></entry>
22272256
</row>
@@ -2279,12 +2308,12 @@ GRANT SELECT (col1), UPDATE (col1) ON mytable TO miriam_rw;
22792308
would show:
22802309
<programlisting>
22812310
=&gt; \dp mytable
2282-
Access privileges
2283-
Schema | Name | Type | Access privileges | Column privileges | Policies
2284-
--------+---------+-------+-----------------------+-----------------------+----------
2285-
public | mytable | table | miriam=arwdDxt/miriam+| col1: +|
2286-
| | | =r/miriam +| miriam_rw=rw/miriam |
2287-
| | | admin=arw/miriam | |
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 | |
22882317
(1 row)
22892318
</programlisting>
22902319
</para>

‎doc/src/sgml/func.sgml

Copy file name to clipboardExpand all lines: doc/src/sgml/func.sgml
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22978,7 +22978,8 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute');
2297822978
are <literal>SELECT</literal>, <literal>INSERT</literal>,
2297922979
<literal>UPDATE</literal>, <literal>DELETE</literal>,
2298022980
<literal>TRUNCATE</literal>, <literal>REFERENCES</literal>,
22981-
and <literal>TRIGGER</literal>.
22981+
<literal>TRIGGER</literal>, <literal>VACUUM</literal> and
22982+
<literal>ANALYZE</literal>.
2298222983
</para></entry>
2298322984
</row>
2298422985

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

Copy file name to clipboardExpand all lines: doc/src/sgml/ref/alter_default_privileges.sgml
+2-2Lines changed: 2 additions & 2 deletions
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 }
31+
GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | VACUUM | ANALYZE }
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 }
54+
{ { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | VACUUM | ANALYZE }
5555
[, ...] | ALL [ PRIVILEGES ] }
5656
ON TABLES
5757
FROM { [ GROUP ] <replaceable class="parameter">role_name</replaceable> | PUBLIC } [, ...]

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

Copy file name to clipboardExpand all lines: doc/src/sgml/ref/analyze.sgml
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,8 @@ ANALYZE [ VERBOSE ] [ <replaceable class="parameter">table_and_columns</replacea
149149

150150
<para>
151151
To analyze a table, one must ordinarily be the table's owner or a
152-
superuser. However, database owners are allowed to
152+
superuser or have the <literal>ANALYZE</literal> privilege on the table.
153+
However, database owners are allowed to
153154
analyze all tables in their databases, except shared catalogs.
154155
(The restriction for shared catalogs means that a true database-wide
155156
<command>ANALYZE</command> can only be performed by a superuser.)

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

Copy file name to clipboardExpand all lines: doc/src/sgml/ref/grant.sgml
+3-1Lines changed: 3 additions & 1 deletion
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 }
24+
GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | VACUUM | ANALYZE }
2525
[, ...] | ALL [ PRIVILEGES ] }
2626
ON { [ TABLE ] <replaceable class="parameter">table_name</replaceable> [, ...]
2727
| ALL TABLES IN SCHEMA <replaceable class="parameter">schema_name</replaceable> [, ...] }
@@ -193,6 +193,8 @@ 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>
196198
<listitem>
197199
<para>
198200
Specific types of privileges, as defined in <xref linkend="ddl-priv"/>.

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

Copy file name to clipboardExpand all lines: doc/src/sgml/ref/revoke.sgml
+1-1Lines changed: 1 addition & 1 deletion
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 }
25+
{ { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | VACUUM | ANALYZE }
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

Copy file name to clipboardExpand all lines: doc/src/sgml/ref/vacuum.sgml
+2-1Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,8 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ <replaceable class="paramet
357357

358358
<para>
359359
To vacuum a table, one must ordinarily be the table's owner or a
360-
superuser. However, database owners are allowed to
360+
superuser or have the <literal>VACUUM</literal> privilege on the table.
361+
However, database owners are allowed to
361362
vacuum all tables in their databases, except shared catalogs.
362363
(The restriction for shared catalogs means that a true database-wide
363364
<command>VACUUM</command> can only be performed by a superuser.)

‎src/backend/catalog/aclchk.c

Copy file name to clipboardExpand all lines: src/backend/catalog/aclchk.c
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3420,6 +3420,10 @@ string_to_privilege(const char *privname)
34203420
return ACL_SET;
34213421
if (strcmp(privname, "alter system") == 0)
34223422
return ACL_ALTER_SYSTEM;
3423+
if (strcmp(privname, "vacuum") == 0)
3424+
return ACL_VACUUM;
3425+
if (strcmp(privname, "analyze") == 0)
3426+
return ACL_ANALYZE;
34233427
if (strcmp(privname, "rule") == 0)
34243428
return 0; /* ignore old RULE privileges */
34253429
ereport(ERROR,
@@ -3461,6 +3465,10 @@ privilege_to_string(AclMode privilege)
34613465
return "SET";
34623466
case ACL_ALTER_SYSTEM:
34633467
return "ALTER SYSTEM";
3468+
case ACL_VACUUM:
3469+
return "VACUUM";
3470+
case ACL_ANALYZE:
3471+
return "ANALYZE";
34643472
default:
34653473
elog(ERROR, "unrecognized privilege: %d", (int) privilege);
34663474
}

‎src/backend/commands/analyze.c

Copy file name to clipboardExpand all lines: src/backend/commands/analyze.c
+6-7Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -159,16 +159,15 @@ analyze_rel(Oid relid, RangeVar *relation,
159159
return;
160160

161161
/*
162-
* Check if relation needs to be skipped based on ownership. This check
162+
* Check if relation needs to be skipped based on privileges. This check
163163
* happens also when building the relation list to analyze for a manual
164164
* operation, and needs to be done additionally here as ANALYZE could
165-
* happen across multiple transactions where relation ownership could have
166-
* changed in-between. Make sure to generate only logs for ANALYZE in
167-
* this case.
165+
* happen across multiple transactions where privileges could have changed
166+
* in-between. Make sure to generate only logs for ANALYZE in this case.
168167
*/
169-
if (!vacuum_is_relation_owner(RelationGetRelid(onerel),
170-
onerel->rd_rel,
171-
params->options & VACOPT_ANALYZE))
168+
if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
169+
onerel->rd_rel,
170+
VACOPT_ANALYZE))
172171
{
173172
relation_close(onerel, ShareUpdateExclusiveLock);
174173
return;

‎src/backend/commands/vacuum.c

Copy file name to clipboardExpand all lines: src/backend/commands/vacuum.c
+33-29Lines changed: 33 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -547,32 +547,35 @@ vacuum(List *relations, VacuumParams *params,
547547
}
548548

549549
/*
550-
* Check if a given relation can be safely vacuumed or analyzed. If the
551-
* user is not the relation owner, issue a WARNING log message and return
552-
* false to let the caller decide what to do with this relation. This
553-
* routine is used to decide if a relation can be processed for VACUUM or
554-
* ANALYZE.
550+
* Check if the current user has privileges to vacuum or analyze the relation.
551+
* If not, issue a WARNING log message and return false to let the caller
552+
* decide what to do with this relation. This routine is used to decide if a
553+
* relation can be processed for VACUUM or ANALYZE.
555554
*/
556555
bool
557-
vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, bits32 options)
556+
vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
557+
bits32 options)
558558
{
559559
char *relname;
560+
AclMode mode = 0;
560561

561562
Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
562563

563564
/*
564-
* Check permissions.
565-
*
566-
* We allow the user to vacuum or analyze a table if he is superuser, the
567-
* table owner, or the database owner (but in the latter case, only if
568-
* it's not a shared relation). object_ownercheck includes the
569-
* superuser case.
570-
*
571-
* Note we choose to treat permissions failure as a WARNING and keep
572-
* trying to vacuum or analyze the rest of the DB --- is this appropriate?
565+
* A role has privileges to vacuum or analyze the relation if any of the
566+
* following are true:
567+
* - the role is a superuser
568+
* - the role owns the relation
569+
* - the role owns the current database and the relation is not shared
570+
* - the role has been granted privileges to vacuum/analyze the relation
573571
*/
572+
if (options & VACOPT_VACUUM)
573+
mode |= ACL_VACUUM;
574+
if (options & VACOPT_ANALYZE)
575+
mode |= ACL_ANALYZE;
574576
if (object_ownercheck(RelationRelationId, relid, GetUserId()) ||
575-
(object_ownercheck(DatabaseRelationId, MyDatabaseId, GetUserId()) && !reltuple->relisshared))
577+
(object_ownercheck(DatabaseRelationId, MyDatabaseId, GetUserId()) && !reltuple->relisshared) ||
578+
pg_class_aclcheck(relid, GetUserId(), mode) == ACLCHECK_OK)
576579
return true;
577580

578581
relname = NameStr(reltuple->relname);
@@ -787,10 +790,10 @@ expand_vacuum_rel(VacuumRelation *vrel, int options)
787790
classForm = (Form_pg_class) GETSTRUCT(tuple);
788791

789792
/*
790-
* Make a returnable VacuumRelation for this rel if user is a proper
791-
* owner.
793+
* Make a returnable VacuumRelation for this rel if the user has the
794+
* required privileges.
792795
*/
793-
if (vacuum_is_relation_owner(relid, classForm, options))
796+
if (vacuum_is_permitted_for_relation(relid, classForm, options))
794797
{
795798
oldcontext = MemoryContextSwitchTo(vac_context);
796799
vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -877,7 +880,7 @@ get_all_vacuum_rels(int options)
877880
Oid relid = classForm->oid;
878881

879882
/* check permissions of relation */
880-
if (!vacuum_is_relation_owner(relid, classForm, options))
883+
if (!vacuum_is_permitted_for_relation(relid, classForm, options))
881884
continue;
882885

883886
/*
@@ -1797,7 +1800,9 @@ vac_truncate_clog(TransactionId frozenXID,
17971800
* be stale.
17981801
*
17991802
* Returns true if it's okay to proceed with a requested ANALYZE
1800-
* operation on this table.
1803+
* operation on this table. Note that if vacuuming fails because the user
1804+
* does not have the required privileges, this function returns true since
1805+
* the user might have been granted privileges to ANALYZE the relation.
18011806
*
18021807
* Doing one heap at a time incurs extra overhead, since we need to
18031808
* check that the heap exists again just before we vacuum it. The
@@ -1889,21 +1894,20 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params)
18891894
}
18901895

18911896
/*
1892-
* Check if relation needs to be skipped based on ownership. This check
1897+
* Check if relation needs to be skipped based on privileges. This check
18931898
* happens also when building the relation list to vacuum for a manual
18941899
* operation, and needs to be done additionally here as VACUUM could
1895-
* happen across multiple transactions where relation ownership could have
1896-
* changed in-between. Make sure to only generate logs for VACUUM in this
1897-
* case.
1900+
* happen across multiple transactions where privileges could have changed
1901+
* in-between. Make sure to only generate logs for VACUUM in this case.
18981902
*/
1899-
if (!vacuum_is_relation_owner(RelationGetRelid(rel),
1900-
rel->rd_rel,
1901-
params->options & VACOPT_VACUUM))
1903+
if (!vacuum_is_permitted_for_relation(RelationGetRelid(rel),
1904+
rel->rd_rel,
1905+
VACOPT_VACUUM))
19021906
{
19031907
relation_close(rel, lmode);
19041908
PopActiveSnapshot();
19051909
CommitTransactionCommand();
1906-
return false;
1910+
return true; /* user might have the ANALYZE privilege */
19071911
}
19081912

19091913
/*

‎src/backend/parser/gram.y

Copy file name to clipboardExpand all lines: src/backend/parser/gram.y
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7482,6 +7482,13 @@ privilege: SELECT opt_column_list
74827482
n->cols = NIL;
74837483
$$ = n;
74847484
}
7485+
| analyze_keyword
7486+
{
7487+
AccessPriv *n = makeNode(AccessPriv);
7488+
n->priv_name = pstrdup("analyze");
7489+
n->cols = NIL;
7490+
$$ = n;
7491+
}
74857492
| ColId opt_column_list
74867493
{
74877494
AccessPriv *n = makeNode(AccessPriv);

‎src/backend/utils/adt/acl.c

Copy file name to clipboardExpand all lines: src/backend/utils/adt/acl.c
+16Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,12 @@ aclparse(const char *s, AclItem *aip)
321321
case ACL_ALTER_SYSTEM_CHR:
322322
read = ACL_ALTER_SYSTEM;
323323
break;
324+
case ACL_VACUUM_CHR:
325+
read = ACL_VACUUM;
326+
break;
327+
case ACL_ANALYZE_CHR:
328+
read = ACL_ANALYZE;
329+
break;
324330
case 'R': /* ignore old RULE privileges */
325331
read = 0;
326332
break;
@@ -1595,6 +1601,8 @@ makeaclitem(PG_FUNCTION_ARGS)
15951601
{"CONNECT", ACL_CONNECT},
15961602
{"SET", ACL_SET},
15971603
{"ALTER SYSTEM", ACL_ALTER_SYSTEM},
1604+
{"VACUUM", ACL_VACUUM},
1605+
{"ANALYZE", ACL_ANALYZE},
15981606
{"RULE", 0}, /* ignore old RULE privileges */
15991607
{NULL, 0}
16001608
};
@@ -1703,6 +1711,10 @@ convert_aclright_to_string(int aclright)
17031711
return "SET";
17041712
case ACL_ALTER_SYSTEM:
17051713
return "ALTER SYSTEM";
1714+
case ACL_VACUUM:
1715+
return "VACUUM";
1716+
case ACL_ANALYZE:
1717+
return "ANALYZE";
17061718
default:
17071719
elog(ERROR, "unrecognized aclright: %d", aclright);
17081720
return NULL;
@@ -2012,6 +2024,10 @@ convert_table_priv_string(text *priv_type_text)
20122024
{"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES)},
20132025
{"TRIGGER", ACL_TRIGGER},
20142026
{"TRIGGER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRIGGER)},
2027+
{"VACUUM", ACL_VACUUM},
2028+
{"VACUUM WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_VACUUM)},
2029+
{"ANALYZE", ACL_ANALYZE},
2030+
{"ANALYZE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_ANALYZE)},
20152031
{"RULE", 0}, /* ignore old RULE privileges */
20162032
{"RULE WITH GRANT OPTION", 0},
20172033
{NULL, 0}

‎src/bin/pg_dump/dumputils.c

Copy file name to clipboardExpand all lines: src/bin/pg_dump/dumputils.c
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,8 @@ do { \
457457
CONVERT_PRIV('d', "DELETE");
458458
CONVERT_PRIV('t', "TRIGGER");
459459
CONVERT_PRIV('D', "TRUNCATE");
460+
CONVERT_PRIV('v', "VACUUM");
461+
CONVERT_PRIV('z', "ANALYZE");
460462
}
461463
}
462464

‎src/bin/pg_dump/t/002_pg_dump.pl

Copy file name to clipboardExpand all lines: src/bin/pg_dump/t/002_pg_dump.pl
+1-1Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -566,7 +566,7 @@
566566
\QREVOKE ALL ON TABLES FROM regress_dump_test_role;\E\n
567567
\QALTER DEFAULT PRIVILEGES \E
568568
\QFOR ROLE regress_dump_test_role \E
569-
\QGRANT INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLES TO regress_dump_test_role;\E
569+
\QGRANT INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,VACUUM,ANALYZE,UPDATE ON TABLES TO regress_dump_test_role;\E
570570
/xm,
571571
like => { %full_runs, section_post_data => 1, },
572572
unlike => { no_privs => 1, },

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.