Revert MAINTAIN privilege and pg_maintain predefined role.
authorNathan Bossart
Fri, 7 Jul 2023 18:25:13 +0000 (11:25 -0700)
committerNathan Bossart
Fri, 7 Jul 2023 18:25:13 +0000 (11:25 -0700)
This reverts the following commits: 4dbdb82513c2122aae63,
5b1a8799439e1e9d6560ff9618e82a60684dd8344441fc704d,
and b5d6382496.  A role with the MAINTAIN privilege may be able to
use search_path tricks to escalate privileges to the table owner.
Unfortunately, it is too late in the v16 development cycle to apply
the proposed fix, i.e., restricting search_path when running
maintenance commands.

Bumps catversion.

Reviewed-by: Jeff Davis
Discussion: https://postgr.es/m/E1q7j7Y-000z1H-Hr%40gemulon.postgresql.org
Backpatch-through: 16

41 files changed:
doc/src/sgml/ddl.sgml
doc/src/sgml/func.sgml
doc/src/sgml/ref/alter_default_privileges.sgml
doc/src/sgml/ref/analyze.sgml
doc/src/sgml/ref/cluster.sgml
doc/src/sgml/ref/grant.sgml
doc/src/sgml/ref/lock.sgml
doc/src/sgml/ref/refresh_materialized_view.sgml
doc/src/sgml/ref/reindex.sgml
doc/src/sgml/ref/revoke.sgml
doc/src/sgml/ref/vacuum.sgml
doc/src/sgml/user-manag.sgml
src/backend/catalog/aclchk.c
src/backend/commands/analyze.c
src/backend/commands/cluster.c
src/backend/commands/indexcmds.c
src/backend/commands/lockcmds.c
src/backend/commands/matview.c
src/backend/commands/tablecmds.c
src/backend/commands/vacuum.c
src/backend/utils/adt/acl.c
src/bin/pg_dump/dumputils.c
src/bin/pg_dump/t/002_pg_dump.pl
src/bin/psql/tab-complete.c
src/include/catalog/catversion.h
src/include/catalog/pg_authid.dat
src/include/commands/tablecmds.h
src/include/commands/vacuum.h
src/include/nodes/parsenodes.h
src/include/utils/acl.h
src/test/isolation/expected/cluster-conflict-partition.out
src/test/isolation/specs/cluster-conflict-partition.spec
src/test/perl/PostgreSQL/Test/AdjustUpgrade.pm
src/test/regress/expected/cluster.out
src/test/regress/expected/create_index.out
src/test/regress/expected/dependency.out
src/test/regress/expected/privileges.out
src/test/regress/expected/rowsecurity.out
src/test/regress/sql/cluster.sql
src/test/regress/sql/dependency.sql
src/test/regress/sql/privileges.sql

index e32f8253d03b4c99a0236a39302a038ae9c9d8a4..43179959658915ec4ec1f79854d73a3780d73397 100644 (file)
@@ -1718,8 +1718,8 @@ ALTER TABLE products RENAME TO items;
    INSERTUPDATEDELETE,
    TRUNCATEREFERENCESTRIGGER,
    CREATECONNECTTEMPORARY,
-   EXECUTEUSAGESET,
-   ALTER SYSTEM, and MAINTAIN.
+   EXECUTEUSAGESET
+   and ALTER SYSTEM.
    The privileges applicable to a particular
    object vary depending on the object's type (table, function, etc.).
    More detail about the meanings of these privileges appears below.
@@ -2010,19 +2010,7 @@ REVOKE ALL ON accounts FROM PUBLIC;
       
      
     
-
-   
-    MAINTAIN
-    
-     
-      Allows VACUUMANALYZE,
-      CLUSTERREFRESH MATERIALIZED VIEW,
-      REINDEX, and LOCK TABLE on a
-      relation.
-     
-    
-   
-  
+   
 
    The privileges required by other commands are listed on the
    reference page of the respective command.
@@ -2171,11 +2159,6 @@ REVOKE ALL ON accounts FROM PUBLIC;
       A
       PARAMETER
      
-     
-      MAINTAIN
-      m
-      TABLE
-     
      
    
   
@@ -2266,7 +2249,7 @@ REVOKE ALL ON accounts FROM PUBLIC;
      
      
       TABLE (and table-like objects)
-      arwdDxtm
+      arwdDxt
       none
       \dp
      
@@ -2325,11 +2308,11 @@ GRANT SELECT (col1), UPDATE (col1) ON mytable TO miriam_rw;
 
 => \dp mytable
                                   Access privileges
- Schema |  Name   | Type  |   Access privileges    |   Column privileges   | Policies
---------+---------+-------+------------------------+-----------------------+----------
- public | mytable | table | miriam=arwdDxtm/miriam+| col1:                +|
-        |         |       | =r/miriam             +|   miriam_rw=rw/miriam |
-        |         |       | admin=arw/miriam       |                       |
+ Schema |  Name   | Type  |   Access privileges   |   Column privileges   | Policies
+--------+---------+-------+-----------------------+-----------------------+----------
+ public | mytable | table | miriam=arwdDxt/miriam+| col1:                +|
+        |         |       | =r/miriam            +|   miriam_rw=rw/miriam |
+        |         |       | admin=arw/miriam      |                       |
 (1 row)
 
   
index 5a47ce4343462ac2cac18d0b291b7c28fe352a75..0b62e0c82850306918d9d475ea9243c0ed1e9cb0 100644 (file)
@@ -23545,7 +23545,7 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute');
         are SELECTINSERT,
         UPDATEDELETE,
         TRUNCATEREFERENCES,
-        TRIGGER, and MAINTAIN.
+        and TRIGGER.
        
       
 
index a33461fbc2f4372e76e71150d53b298772a98a68..f1d54f5aa35f9ce1e50d7d13cd926d92554e4e9e 100644 (file)
@@ -28,7 +28,7 @@ ALTER DEFAULT PRIVILEGES
 
 where abbreviated_grant_or_revoke is one of:
 
-GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | MAINTAIN }
+GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
     [, ...] | ALL [ PRIVILEGES ] }
     ON TABLES
     TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]
@@ -51,7 +51,7 @@ GRANT { USAGE | CREATE | ALL [ PRIVILEGES ] }
     TO { [ GROUP ] role_name | PUBLIC } [, ...] [ WITH GRANT OPTION ]
 
 REVOKE [ GRANT OPTION FOR ]
-    { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | MAINTAIN }
+    { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
     [, ...] | ALL [ PRIVILEGES ] }
     ON TABLES
     FROM { [ GROUP ] role_name | PUBLIC } [, ...]
index 954491b5df0f4545731b66cf0fe4baa3cdccd067..aa3e9e1c5fe5b936bb42b4fc382a0192240e680f 100644 (file)
@@ -182,9 +182,11 @@ ANALYZE [ VERBOSE ] [ table_and_columns
   Notes
 
   
-   To analyze a table, one must ordinarily have the MAINTAIN
-   privilege on the table.  However, database owners are allowed to
+   To analyze a table, one must ordinarily be the table's owner or a
+   superuser.  However, database owners are allowed to
    analyze all tables in their databases, except shared catalogs.
+   (The restriction for shared catalogs means that a true database-wide
+   ANALYZE can only be performed by a superuser.)
    ANALYZE will skip over any tables that the calling user
    does not have permission to analyze.
   
index 06f3d269e67bc4b7556c2abdeda6ba36ccd5215a..0ed29a5c6d404ff3eeeb156bd54b7af873271004 100644 (file)
@@ -70,8 +70,9 @@ CLUSTER [VERBOSE]
    CLUSTER without a
    table_name reclusters all the
    previously-clustered tables in the current database that the calling user
-   has privileges for.  This form of CLUSTER cannot be
-   executed inside a transaction block.
+   owns, or all such tables if called by a superuser.  This
+   form of CLUSTER cannot be executed inside a transaction
+   block.
   
 
   
@@ -132,11 +133,6 @@ CLUSTER [VERBOSE]
  
   Notes
 
-   
-    To cluster a table, one must have the MAINTAIN privilege
-    on the table.
-   
-
    
     In cases where you are accessing single rows randomly
     within a table, the actual order of the data in the
index 35bf0332c8fc37322777bf74278ec95481822a65..1ae5770fbbf3203382ca71d1072bfe1927fee481 100644 (file)
@@ -21,7 +21,7 @@ PostgreSQL documentation
 
  
 
-GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | MAINTAIN }
+GRANT { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
     [, ...] | ALL [ PRIVILEGES ] }
     ON { [ TABLE ] table_name [, ...]
          | ALL TABLES IN SCHEMA schema_name [, ...] }
@@ -193,7 +193,6 @@ GRANT role_name [, ...] TO 
      USAGE
      SET
      ALTER SYSTEM
-     MAINTAIN
      
       
        Specific types of privileges, as defined in .
index 070855da18b2a5a4385917eb852662ee0b27fb87..6ce2518de74b8d5d7aaa355657606cc95294ce67 100644 (file)
@@ -166,8 +166,8 @@ LOCK [ TABLE ] [ ONLY ] name [ * ]
 
    
     To lock a table, the user must have the right privilege for the specified
-    lockmode.
-    If the user has MAINTAIN,
+    lockmode, or be the table's
+    owner or a superuser.  If the user has
     UPDATEDELETE, or
     TRUNCATE privileges on the table, any 
     class="parameter">lockmode is permitted. If the user has
index 19737668cdb2af65bfa4e45a089af50d03e940c4..675d6090f3cd68b17da2ccfa1db851641795b47e 100644 (file)
@@ -31,9 +31,8 @@ REFRESH MATERIALIZED VIEW [ CONCURRENTLY ] name
 
   
    REFRESH MATERIALIZED VIEW completely replaces the
-   contents of a materialized view.  To execute this command you must have the
-   MAINTAIN
-   privilege on the materialized view.  The old contents are discarded.  If
+   contents of a materialized view.  To execute this command you must be the
+   owner of the materialized view.  The old contents are discarded.  If
    WITH DATA is specified (or defaults) the backing query
    is executed to provide the new data, and the materialized view is left in a
    scannable state.  If WITH NO DATA is specified no new
index bef3486843cabd9a1fc5242ea05ed1a539435509..21e2e91d896c479c4614cf34015e46f018a559c2 100644 (file)
@@ -292,21 +292,16 @@ REINDEX [ ( option [, ...] ) ] { DA
   
 
   
-   Reindexing a single index or table requires
-   having the MAINTAIN privilege on the
-   table.  Note that while REINDEX on a partitioned index or
-   table requires having the MAINTAIN privilege on the
-   partitioned table, such commands skip the privilege checks when processing
-   the individual partitions.  Reindexing a schema or database requires being the
-   owner of that schema or database or having privileges of the
-   pg_maintain
-   role.  Note specifically that it's thus
+   Reindexing a single index or table requires being the owner of that
+   index or table.  Reindexing a schema or database requires being the
+   owner of that schema or database.  Note specifically that it's thus
    possible for non-superusers to rebuild indexes of tables owned by
-   other users.  However, as a special exception,
-   REINDEX DATABASEREINDEX SCHEMA,
-   and REINDEX SYSTEM will skip indexes on shared catalogs
-   unless the user has the MAINTAIN privilege on the
-   catalog.
+   other users.  However, as a special exception, when
+   REINDEX DATABASEREINDEX SCHEMA
+   or REINDEX SYSTEM is issued by a non-superuser,
+   indexes on shared catalogs will be skipped unless the user owns the
+   catalog (which typically won't be the case).  Of course, superusers
+   can always reindex anything.
   
 
   
index 8df492281a1c519754da38197b0a865c8a30c94d..2db66bbf378e22c4fa4f1989ead18468d1fd24e0 100644 (file)
@@ -22,7 +22,7 @@ PostgreSQL documentation
  
 
 REVOKE [ GRANT OPTION FOR ]
-    { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER | MAINTAIN }
+    { { SELECT | INSERT | UPDATE | DELETE | TRUNCATE | REFERENCES | TRIGGER }
     [, ...] | ALL [ PRIVILEGES ] }
     ON { [ TABLE ] table_name [, ...]
          | ALL TABLES IN SCHEMA schema_name [, ...] }
index c42bbea9e228e0d00c0ea7dc8a0f8ad063635312..65c03bf8299d8df6c4cede602c206694d0290a5a 100644 (file)
@@ -444,9 +444,11 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ 
   Notes
 
    
-    To vacuum a table, one must ordinarily have the MAINTAIN
-    privilege on the table.  However, database owners are allowed to
+    To vacuum a table, one must ordinarily be the table's owner or a
+    superuser.  However, database owners are allowed to
     vacuum all tables in their databases, except shared catalogs.
+    (The restriction for shared catalogs means that a true database-wide
+    VACUUM can only be performed by a superuser.)
     VACUUM will skip over any tables that the calling user
     does not have permission to vacuum.
    
index e1540dd481b0c09dc892322369f321dcdbef0226..27c1f3d7032a332ff2bded649a2ff87c69baaea6 100644 (file)
@@ -683,18 +683,6 @@ DROP ROLE doomed_role;
        the CHECKPOINT
        command.
       
-      
-       pg_maintain
-       Allow executing
-       VACUUM,
-       ANALYZE,
-       CLUSTER,
-       REFRESH MATERIALIZED VIEW,
-       REINDEX,
-       and LOCK TABLE on all
-       relations, as if having MAINTAIN rights on those
-       objects, even without having it explicitly.
-      
       
        pg_use_reserved_connections
        Allow use of connection slots reserved via
index bc2ad773c90b5e04f4d8094ff87aa30946cf10d5..d1f5dcd8bed1ea7b1e304c8c2cce316328f5611d 100644 (file)
@@ -2612,8 +2612,6 @@ string_to_privilege(const char *privname)
        return ACL_SET;
    if (strcmp(privname, "alter system") == 0)
        return ACL_ALTER_SYSTEM;
-   if (strcmp(privname, "maintain") == 0)
-       return ACL_MAINTAIN;
    if (strcmp(privname, "rule") == 0)
        return 0;               /* ignore old RULE privileges */
    ereport(ERROR,
@@ -2655,8 +2653,6 @@ privilege_to_string(AclMode privilege)
            return "SET";
        case ACL_ALTER_SYSTEM:
            return "ALTER SYSTEM";
-       case ACL_MAINTAIN:
-           return "MAINTAIN";
        default:
            elog(ERROR, "unrecognized privilege: %d", (int) privilege);
    }
@@ -3388,17 +3384,6 @@ pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask,
        has_privs_of_role(roleid, ROLE_PG_WRITE_ALL_DATA))
        result |= (mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE));
 
-   /*
-    * Check if ACL_MAINTAIN is being checked and, if so, and not already set
-    * as part of the result, then check if the user is a member of the
-    * pg_maintain role, which allows VACUUM, ANALYZE, CLUSTER, REFRESH
-    * MATERIALIZED VIEW, and REINDEX on all relations.
-    */
-   if (mask & ACL_MAINTAIN &&
-       !(result & ACL_MAINTAIN) &&
-       has_privs_of_role(roleid, ROLE_PG_MAINTAIN))
-       result |= ACL_MAINTAIN;
-
    return result;
 }
 
index 9c8413eef23590a858f3c7bc2a5eef9b9bb83c83..bfd981aa3f370fcd70c5eea3ed144caf52154175 100644 (file)
@@ -159,15 +159,16 @@ analyze_rel(Oid relid, RangeVar *relation,
        return;
 
    /*
-    * Check if relation needs to be skipped based on privileges.  This check
+    * Check if relation needs to be skipped based on ownership.  This check
     * happens also when building the relation list to analyze for a manual
     * operation, and needs to be done additionally here as ANALYZE could
-    * happen across multiple transactions where privileges could have changed
-    * in-between.  Make sure to generate only logs for ANALYZE in this case.
+    * happen across multiple transactions where relation ownership could have
+    * changed in-between.  Make sure to generate only logs for ANALYZE in
+    * this case.
     */
-   if (!vacuum_is_permitted_for_relation(RelationGetRelid(onerel),
-                                         onerel->rd_rel,
-                                         params->options & ~VACOPT_VACUUM))
+   if (!vacuum_is_relation_owner(RelationGetRelid(onerel),
+                                 onerel->rd_rel,
+                                 params->options & VACOPT_ANALYZE))
    {
        relation_close(onerel, ShareUpdateExclusiveLock);
        return;
index 03b24ab90f156c66fc00406a668caf44ded14abe..92c465c05b4775e64f7960b44c6b394387627f92 100644 (file)
@@ -80,7 +80,6 @@ static void copy_table_data(Oid OIDNewHeap, Oid OIDOldHeap, Oid OIDOldIndex,
 static List *get_tables_to_cluster(MemoryContext cluster_context);
 static List *get_tables_to_cluster_partitioned(MemoryContext cluster_context,
                                               Oid indexOid);
-static bool cluster_is_permitted_for_relation(Oid relid, Oid userid);
 
 
 /*---------------------------------------------------------------------------
@@ -148,8 +147,7 @@ cluster(ParseState *pstate, ClusterStmt *stmt, bool isTopLevel)
        tableOid = RangeVarGetRelidExtended(stmt->relation,
                                            AccessExclusiveLock,
                                            0,
-                                           RangeVarCallbackMaintainsTable,
-                                           NULL);
+                                           RangeVarCallbackOwnsTable, NULL);
        rel = table_open(tableOid, NoLock);
 
        /*
@@ -366,8 +364,8 @@ cluster_rel(Oid tableOid, Oid indexOid, ClusterParams *params)
     */
    if (recheck)
    {
-       /* Check that the user still has privileges for the relation */
-       if (!cluster_is_permitted_for_relation(tableOid, save_userid))
+       /* Check that the user still owns the relation */
+       if (!object_ownercheck(RelationRelationId, tableOid, save_userid))
        {
            relation_close(OldHeap, AccessExclusiveLock);
            goto out;
@@ -1642,7 +1640,7 @@ finish_heap_swap(Oid OIDOldHeap, Oid OIDNewHeap,
 
 
 /*
- * Get a list of tables that the current user has privileges on and
+ * Get a list of tables that the current user owns and
  * have indisclustered set.  Return the list in a List * of RelToCluster
  * (stored in the specified memory context), each one giving the tableOid
  * and the indexOid on which the table is already clustered.
@@ -1659,8 +1657,8 @@ get_tables_to_cluster(MemoryContext cluster_context)
    List       *rtcs = NIL;
 
    /*
-    * Get all indexes that have indisclustered set and that the current user
-    * has the appropriate privileges for.
+    * Get all indexes that have indisclustered set and are owned by
+    * appropriate user.
     */
    indRelation = table_open(IndexRelationId, AccessShareLock);
    ScanKeyInit(&entry,
@@ -1674,7 +1672,7 @@ get_tables_to_cluster(MemoryContext cluster_context)
 
        index = (Form_pg_index) GETSTRUCT(indexTuple);
 
-       if (!cluster_is_permitted_for_relation(index->indrelid, GetUserId()))
+       if (!object_ownercheck(RelationRelationId, index->indrelid, GetUserId()))
            continue;
 
        /* Use a permanent memory context for the result list */
@@ -1722,13 +1720,10 @@ get_tables_to_cluster_partitioned(MemoryContext cluster_context, Oid indexOid)
        if (get_rel_relkind(indexrelid) != RELKIND_INDEX)
            continue;
 
-       /*
-        * It's possible that the user does not have privileges to CLUSTER the
-        * leaf partition despite having such privileges on the partitioned
-        * table.  We skip any partitions which the user is not permitted to
-        * CLUSTER.
-        */
-       if (!cluster_is_permitted_for_relation(relid, GetUserId()))
+       /* Silently skip partitions which the user has no access to. */
+       if (!object_ownercheck(RelationRelationId, relid, GetUserId()) &&
+           (!object_ownercheck(DatabaseRelationId, MyDatabaseId, GetUserId()) ||
+            IsSharedRelation(relid)))
            continue;
 
        /* Use a permanent memory context for the result list */
@@ -1744,19 +1739,3 @@ get_tables_to_cluster_partitioned(MemoryContext cluster_context, Oid indexOid)
 
    return rtcs;
 }
-
-/*
- * Return whether userid has privileges to CLUSTER relid.  If not, this
- * function emits a WARNING.
- */
-static bool
-cluster_is_permitted_for_relation(Oid relid, Oid userid)
-{
-   if (pg_class_aclcheck(relid, userid, ACL_MAINTAIN) == ACLCHECK_OK)
-       return true;
-
-   ereport(WARNING,
-           (errmsg("permission denied to cluster \"%s\", skipping it",
-                   get_rel_name(relid))));
-   return false;
-}
index 403f5fc143f1516c16dde94c0c3c21d84e38b0a3..02250ae74be6423e8eb5d02476bc5cf45106c945 100644 (file)
@@ -26,7 +26,6 @@
 #include "catalog/index.h"
 #include "catalog/indexing.h"
 #include "catalog/pg_am.h"
-#include "catalog/pg_authid.h"
 #include "catalog/pg_constraint.h"
 #include "catalog/pg_database.h"
 #include "catalog/pg_inherits.h"
@@ -2829,7 +2828,6 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation,
    char        relkind;
    struct ReindexIndexCallbackState *state = arg;
    LOCKMODE    table_lockmode;
-   Oid         table_oid;
 
    /*
     * Lock level here should match table lock in reindex_index() for
@@ -2869,19 +2867,14 @@ RangeVarCallbackForReindexIndex(const RangeVar *relation,
                 errmsg("\"%s\" is not an index", relation->relname)));
 
    /* Check permissions */
-   table_oid = IndexGetRelation(relId, true);
-   if (OidIsValid(table_oid))
-   {
-       AclResult   aclresult;
-
-       aclresult = pg_class_aclcheck(table_oid, GetUserId(), ACL_MAINTAIN);
-       if (aclresult != ACLCHECK_OK)
-           aclcheck_error(aclresult, OBJECT_INDEX, relation->relname);
-   }
+   if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
+       aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_INDEX, relation->relname);
 
    /* Lock heap before index to avoid deadlock. */
    if (relId != oldRelId)
    {
+       Oid         table_oid = IndexGetRelation(relId, true);
+
        /*
         * If the OID isn't valid, it means the index was concurrently
         * dropped, which is not a problem for us; just return normally.
@@ -2916,7 +2909,7 @@ ReindexTable(RangeVar *relation, ReindexParams *params, bool isTopLevel)
                                       (params->options & REINDEXOPT_CONCURRENTLY) != 0 ?
                                       ShareUpdateExclusiveLock : ShareLock,
                                       0,
-                                      RangeVarCallbackMaintainsTable, NULL);
+                                      RangeVarCallbackOwnsTable, NULL);
 
    if (get_rel_relkind(heapOid) == RELKIND_PARTITIONED_TABLE)
        ReindexPartitions(heapOid, params, isTopLevel);
@@ -2998,8 +2991,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
    {
        objectOid = get_namespace_oid(objectName, false);
 
-       if (!object_ownercheck(NamespaceRelationId, objectOid, GetUserId()) &&
-           !has_privs_of_role(GetUserId(), ROLE_PG_MAINTAIN))
+       if (!object_ownercheck(NamespaceRelationId, objectOid, GetUserId()))
            aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_SCHEMA,
                           objectName);
    }
@@ -3011,8 +3003,7 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
            ereport(ERROR,
                    (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                     errmsg("can only reindex the currently open database")));
-       if (!object_ownercheck(DatabaseRelationId, objectOid, GetUserId()) &&
-           !has_privs_of_role(GetUserId(), ROLE_PG_MAINTAIN))
+       if (!object_ownercheck(DatabaseRelationId, objectOid, GetUserId()))
            aclcheck_error(ACLCHECK_NOT_OWNER, OBJECT_DATABASE,
                           get_database_name(objectOid));
    }
@@ -3084,12 +3075,15 @@ ReindexMultipleTables(const char *objectName, ReindexObjectType objectKind,
            continue;
 
        /*
-        * We already checked privileges on the database or schema, but we
-        * further restrict reindexing shared catalogs to roles with the
-        * MAINTAIN privilege on the relation.
+        * The table can be reindexed if the user is superuser, the table
+        * owner, or the database/schema owner (but in the latter case, only
+        * if it's not a shared relation).  object_ownercheck includes the
+        * superuser case, and depending on objectKind we already know that
+        * the user has permission to run REINDEX on this database or schema
+        * per the permission checks at the beginning of this routine.
         */
        if (classtuple->relisshared &&
-           pg_class_aclcheck(relid, GetUserId(), ACL_MAINTAIN) != ACLCHECK_OK)
+           !object_ownercheck(RelationRelationId, relid, GetUserId()))
            continue;
 
        /*
index 92662cbbc8768ee777ee750c549f6ea266f5b007..40ef4ede26f1fdc989315572d90dbf6ca0b84208 100644 (file)
@@ -284,7 +284,7 @@ LockTableAclCheck(Oid reloid, LOCKMODE lockmode, Oid userid)
    AclMode     aclmask;
 
    /* any of these privileges permit any lock mode */
-   aclmask = ACL_MAINTAIN | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE;
+   aclmask = ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE;
 
    /* SELECT privileges also permit ACCESS SHARE and below */
    if (lockmode <= AccessShareLock)
index f9a3bdfc3abbff2bc2ad5d78252d5f91f3967a67..ac2e74fa3fbbfb35ee269adf4ba3880260739fa2 100644 (file)
@@ -165,8 +165,7 @@ ExecRefreshMatView(RefreshMatViewStmt *stmt, const char *queryString,
     */
    matviewOid = RangeVarGetRelidExtended(stmt->relation,
                                          lockmode, 0,
-                                         RangeVarCallbackMaintainsTable,
-                                         NULL);
+                                         RangeVarCallbackOwnsTable, NULL);
    matviewRel = table_open(matviewOid, NoLock);
    relowner = matviewRel->rd_rel->relowner;
 
index fce5e6f22095aa4bd5e5993faad80898a8fcc7f4..5316f5830810043c795dde19b15675e8d683c8aa 100644 (file)
@@ -16978,16 +16978,15 @@ AtEOSubXact_on_commit_actions(bool isCommit, SubTransactionId mySubid,
  * This is intended as a callback for RangeVarGetRelidExtended().  It allows
  * the relation to be locked only if (1) it's a plain or partitioned table,
  * materialized view, or TOAST table and (2) the current user is the owner (or
- * the superuser) or has been granted MAINTAIN.  This meets the
- * permission-checking needs of CLUSTER, REINDEX TABLE, and REFRESH
- * MATERIALIZED VIEW; we expose it here so that it can be used by all.
+ * the superuser).  This meets the permission-checking needs of CLUSTER,
+ * REINDEX TABLE, and REFRESH MATERIALIZED VIEW; we expose it here so that it
+ * can be used by all.
  */
 void
-RangeVarCallbackMaintainsTable(const RangeVar *relation,
-                              Oid relId, Oid oldRelId, void *arg)
+RangeVarCallbackOwnsTable(const RangeVar *relation,
+                         Oid relId, Oid oldRelId, void *arg)
 {
    char        relkind;
-   AclResult   aclresult;
 
    /* Nothing to do if the relation was not found. */
    if (!OidIsValid(relId))
@@ -17008,9 +17007,8 @@ RangeVarCallbackMaintainsTable(const RangeVar *relation,
                 errmsg("\"%s\" is not a table or materialized view", relation->relname)));
 
    /* Check permissions */
-   aclresult = pg_class_aclcheck(relId, GetUserId(), ACL_MAINTAIN);
-   if (aclresult != ACLCHECK_OK)
-       aclcheck_error(aclresult, OBJECT_TABLE, relation->relname);
+   if (!object_ownercheck(RelationRelationId, relId, GetUserId()))
+       aclcheck_error(ACLCHECK_NOT_OWNER, get_relkind_objtype(get_rel_relkind(relId)), relation->relname);
 }
 
 /*
index 7fe6a54c068f44a19dfa64a378620b1c9d410305..57ca41add2f0eb1db29be607da63f35d04f80543 100644 (file)
@@ -697,35 +697,32 @@ vacuum(List *relations, VacuumParams *params, BufferAccessStrategy bstrategy,
 }
 
 /*
- * Check if the current user has privileges to vacuum or analyze the relation.
- * If not, issue a WARNING log message and return false to let the caller
- * decide what to do with this relation.  This routine is used to decide if a
- * relation can be processed for VACUUM or ANALYZE.
+ * Check if a given relation can be safely vacuumed or analyzed.  If the
+ * user is not the relation owner, issue a WARNING log message and return
+ * false to let the caller decide what to do with this relation.  This
+ * routine is used to decide if a relation can be processed for VACUUM or
+ * ANALYZE.
  */
 bool
-vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-                                bits32 options)
+vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple, bits32 options)
 {
    char       *relname;
 
    Assert((options & (VACOPT_VACUUM | VACOPT_ANALYZE)) != 0);
 
    /*
-    * Privilege checks are bypassed in some cases (e.g., when recursing to a
-    * relation's TOAST table).
-    */
-   if (options & VACOPT_SKIP_PRIVS)
-       return true;
-
-   /*----------
-    * A role has privileges to vacuum or analyze the relation if any of the
-    * following are true:
-    *   - the role owns the current database and the relation is not shared
-    *   - the role has the MAINTAIN privilege on the relation
-    *----------
+    * Check permissions.
+    *
+    * We allow the user to vacuum or analyze a table if he is superuser, the
+    * table owner, or the database owner (but in the latter case, only if
+    * it's not a shared relation).  object_ownercheck includes the superuser
+    * case.
+    *
+    * Note we choose to treat permissions failure as a WARNING and keep
+    * trying to vacuum or analyze the rest of the DB --- is this appropriate?
     */
-   if ((object_ownercheck(DatabaseRelationId, MyDatabaseId, GetUserId()) && !reltuple->relisshared) ||
-       pg_class_aclcheck(relid, GetUserId(), ACL_MAINTAIN) == ACLCHECK_OK)
+   if (object_ownercheck(RelationRelationId, relid, GetUserId()) ||
+       (object_ownercheck(DatabaseRelationId, MyDatabaseId, GetUserId()) && !reltuple->relisshared))
        return true;
 
    relname = NameStr(reltuple->relname);
@@ -941,10 +938,10 @@ expand_vacuum_rel(VacuumRelation *vrel, MemoryContext vac_context,
        classForm = (Form_pg_class) GETSTRUCT(tuple);
 
        /*
-        * Make a returnable VacuumRelation for this rel if the user has the
-        * required privileges.
+        * Make a returnable VacuumRelation for this rel if user is a proper
+        * owner.
         */
-       if (vacuum_is_permitted_for_relation(relid, classForm, options))
+       if (vacuum_is_relation_owner(relid, classForm, options))
        {
            oldcontext = MemoryContextSwitchTo(vac_context);
            vacrels = lappend(vacrels, makeVacuumRelation(vrel->relation,
@@ -1041,7 +1038,7 @@ get_all_vacuum_rels(MemoryContext vac_context, int options)
            continue;
 
        /* check permissions of relation */
-       if (!vacuum_is_permitted_for_relation(relid, classForm, options))
+       if (!vacuum_is_relation_owner(relid, classForm, options))
            continue;
 
        /*
@@ -2034,15 +2031,16 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
    }
 
    /*
-    * Check if relation needs to be skipped based on privileges.  This check
+    * Check if relation needs to be skipped based on ownership.  This check
     * happens also when building the relation list to vacuum for a manual
     * operation, and needs to be done additionally here as VACUUM could
-    * happen across multiple transactions where privileges could have changed
-    * in-between.  Make sure to only generate logs for VACUUM in this case.
+    * happen across multiple transactions where relation ownership could have
+    * changed in-between.  Make sure to only generate logs for VACUUM in this
+    * case.
     */
-   if (!vacuum_is_permitted_for_relation(RelationGetRelid(rel),
-                                         rel->rd_rel,
-                                         params->options & ~VACOPT_ANALYZE))
+   if (!vacuum_is_relation_owner(RelationGetRelid(rel),
+                                 rel->rd_rel,
+                                 params->options & VACOPT_VACUUM))
    {
        relation_close(rel, lmode);
        PopActiveSnapshot();
@@ -2228,14 +2226,9 @@ vacuum_rel(Oid relid, RangeVar *relation, VacuumParams *params,
    {
        VacuumParams toast_vacuum_params;
 
-       /*
-        * Force VACOPT_PROCESS_MAIN so vacuum_rel() processes it.  Likewise,
-        * set VACOPT_SKIP_PRIVS since privileges on the main relation are
-        * sufficient to process it.
-        */
+       /* force VACOPT_PROCESS_MAIN so vacuum_rel() processes it */
        memcpy(&toast_vacuum_params, params, sizeof(VacuumParams));
        toast_vacuum_params.options |= VACOPT_PROCESS_MAIN;
-       toast_vacuum_params.options |= VACOPT_SKIP_PRIVS;
 
        vacuum_rel(toast_relid, NULL, &toast_vacuum_params, bstrategy);
    }
index c660fd3e7018e66c9dec7f546e97d93151885959..883e09393a497029742b6981efcab25e7f640fbc 100644 (file)
@@ -332,9 +332,6 @@ aclparse(const char *s, AclItem *aip, Node *escontext)
            case ACL_ALTER_SYSTEM_CHR:
                read = ACL_ALTER_SYSTEM;
                break;
-           case ACL_MAINTAIN_CHR:
-               read = ACL_MAINTAIN;
-               break;
            case 'R':           /* ignore old RULE privileges */
                read = 0;
                break;
@@ -1626,7 +1623,6 @@ makeaclitem(PG_FUNCTION_ARGS)
        {"CONNECT", ACL_CONNECT},
        {"SET", ACL_SET},
        {"ALTER SYSTEM", ACL_ALTER_SYSTEM},
-       {"MAINTAIN", ACL_MAINTAIN},
        {"RULE", 0},            /* ignore old RULE privileges */
        {NULL, 0}
    };
@@ -1735,8 +1731,6 @@ convert_aclright_to_string(int aclright)
            return "SET";
        case ACL_ALTER_SYSTEM:
            return "ALTER SYSTEM";
-       case ACL_MAINTAIN:
-           return "MAINTAIN";
        default:
            elog(ERROR, "unrecognized aclright: %d", aclright);
            return NULL;
@@ -2046,8 +2040,6 @@ convert_table_priv_string(text *priv_type_text)
        {"REFERENCES WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_REFERENCES)},
        {"TRIGGER", ACL_TRIGGER},
        {"TRIGGER WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_TRIGGER)},
-       {"MAINTAIN", ACL_MAINTAIN},
-       {"MAINTAIN WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_MAINTAIN)},
        {"RULE", 0},            /* ignore old RULE privileges */
        {"RULE WITH GRANT OPTION", 0},
        {NULL, 0}
index 0ea96346cb015361cd3ef7dbe95f6f40a1d51eff..d2851cf568ea84e75d96c68aee5c7600741aa232 100644 (file)
@@ -463,7 +463,6 @@ do { \
                CONVERT_PRIV('d', "DELETE");
                CONVERT_PRIV('t', "TRIGGER");
                CONVERT_PRIV('D', "TRUNCATE");
-               CONVERT_PRIV('m', "MAINTAIN");
            }
        }
 
index 63bb4689d448c3853cec2a1ba6c65bd4635ac9bf..d42243bf71e9ccfd15acabb570b961bd02151943 100644 (file)
@@ -794,7 +794,7 @@ my %tests = (
            \QREVOKE ALL ON TABLES FROM regress_dump_test_role;\E\n
            \QALTER DEFAULT PRIVILEGES \E
            \QFOR ROLE regress_dump_test_role \E
-           \QGRANT INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,MAINTAIN,UPDATE ON TABLES TO regress_dump_test_role;\E
+           \QGRANT INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLES TO regress_dump_test_role;\E
            /xm,
        like => { %full_runs, section_post_data => 1, },
        unlike => { no_privs => 1, },
index 935bb9bd955a8448c8d19bd900238cf801513e34..e9fddd91ebfbab986fdba57d29e6e11861ebdc39 100644 (file)
@@ -1151,7 +1151,7 @@ Keywords_for_list_of_owner_roles, "PUBLIC"
 #define Privilege_options_of_grant_and_revoke \
 "SELECT", "INSERT", "UPDATE", "DELETE", "TRUNCATE", "REFERENCES", "TRIGGER", \
 "CREATE", "CONNECT", "TEMPORARY", "EXECUTE", "USAGE", "SET", "ALTER SYSTEM", \
-"MAINTAIN", "ALL"
+"ALL"
 
 /* ALTER PROCEDURE options */
 #define Alter_procedure_options \
@@ -3881,7 +3881,7 @@ psql_completion(const char *text, int start, int end)
        if (HeadMatches("ALTER", "DEFAULT", "PRIVILEGES"))
            COMPLETE_WITH("SELECT", "INSERT", "UPDATE",
                          "DELETE", "TRUNCATE", "REFERENCES", "TRIGGER",
-                         "CREATE", "EXECUTE", "USAGE", "MAINTAIN", "ALL");
+                         "CREATE", "EXECUTE", "USAGE", "ALL");
        else if (TailMatches("GRANT"))
            COMPLETE_WITH_QUERY_PLUS(Query_for_list_of_roles,
                                     Privilege_options_of_grant_and_revoke);
@@ -3933,7 +3933,7 @@ psql_completion(const char *text, int start, int end)
    else if (TailMatches("GRANT|REVOKE", MatchAny) ||
             TailMatches("REVOKE", "GRANT", "OPTION", "FOR", MatchAny))
    {
-       if (TailMatches("SELECT|INSERT|UPDATE|DELETE|TRUNCATE|REFERENCES|TRIGGER|CREATE|CONNECT|TEMPORARY|TEMP|EXECUTE|USAGE|MAINTAIN|ALL"))
+       if (TailMatches("SELECT|INSERT|UPDATE|DELETE|TRUNCATE|REFERENCES|TRIGGER|CREATE|CONNECT|TEMPORARY|TEMP|EXECUTE|USAGE|ALL"))
            COMPLETE_WITH("ON");
        else if (TailMatches("GRANT", MatchAny))
            COMPLETE_WITH("TO");
index b0c557a828d9cb973e6d0dfe4b1aeaef9731c7fd..83f3a7c2eca5b6a4220d6c34b55bfe67620472a0 100644 (file)
@@ -57,6 +57,6 @@
  */
 
 /*                         yyyymmddN */
-#define CATALOG_VERSION_NO 202307031
+#define CATALOG_VERSION_NO 202307072
 
 #endif
index 1d7e00b2fddef52df81f60b51483db1a4c6aee4b..6b4a0aaaad996934945c00db793f5a6918deae80 100644 (file)
   rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f',
   rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1',
   rolpassword => '_null_', rolvaliduntil => '_null_' },
-{ oid => '4549', oid_symbol => 'ROLE_PG_MAINTAIN',
-  rolname => 'pg_maintain', rolsuper => 'f', rolinherit => 't',
-  rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f',
-  rolreplication => 'f', rolbypassrls => 'f', rolconnlimit => '-1',
-  rolpassword => '_null_', rolvaliduntil => '_null_' },
 { oid => '4550', oid_symbol => 'ROLE_PG_USE_RESERVED_CONNECTIONS',
   rolname => 'pg_use_reserved_connections', rolsuper => 'f', rolinherit => 't',
   rolcreaterole => 'f', rolcreatedb => 'f', rolcanlogin => 'f',
index 250d89ff88b559933f131615c801afa709c8852e..16b61266690f7878739ffd9943fb8dc6cf28f6f4 100644 (file)
@@ -96,9 +96,8 @@ extern void AtEOSubXact_on_commit_actions(bool isCommit,
                                          SubTransactionId mySubid,
                                          SubTransactionId parentSubid);
 
-extern void RangeVarCallbackMaintainsTable(const RangeVar *relation,
-                                          Oid relId, Oid oldRelId,
-                                          void *arg);
+extern void RangeVarCallbackOwnsTable(const RangeVar *relation,
+                                     Oid relId, Oid oldRelId, void *arg);
 
 extern void RangeVarCallbackOwnsRelation(const RangeVar *relation,
                                         Oid relId, Oid oldRelId, void *arg);
index b027fb2c67f65ba49d5046666e95f35e466db3eb..4af02940c5467cd34d5323ca643a088160a812a7 100644 (file)
@@ -187,7 +187,6 @@ typedef struct VacAttrStats
 #define VACOPT_DISABLE_PAGE_SKIPPING 0x100 /* don't skip any pages */
 #define VACOPT_SKIP_DATABASE_STATS 0x200   /* skip vac_update_datfrozenxid() */
 #define VACOPT_ONLY_DATABASE_STATS 0x400   /* only vac_update_datfrozenxid() */
-#define VACOPT_SKIP_PRIVS 0x800 /* skip privilege checks */
 
 /*
  * Values used by index_cleanup and truncate params.
@@ -344,8 +343,8 @@ extern bool vacuum_get_cutoffs(Relation rel, const VacuumParams *params,
 extern bool vacuum_xid_failsafe_check(const struct VacuumCutoffs *cutoffs);
 extern void vac_update_datfrozenxid(void);
 extern void vacuum_delay_point(void);
-extern bool vacuum_is_permitted_for_relation(Oid relid, Form_pg_class reltuple,
-                                            bits32 options);
+extern bool vacuum_is_relation_owner(Oid relid, Form_pg_class reltuple,
+                                    bits32 options);
 extern Relation vacuum_open_relation(Oid relid, RangeVar *relation,
                                     bits32 options, bool verbose,
                                     LOCKMODE lmode);
index 88b03cc4725934fa85e1033ea4811da1bf4060e0..efb5c3e098b21ac8e9b3469be4eb24147f99b476 100644 (file)
@@ -94,8 +94,7 @@ typedef uint64 AclMode;           /* a bitmask of privilege bits */
 #define ACL_CONNECT        (1<<11) /* for databases */
 #define ACL_SET            (1<<12) /* for configuration parameters */
 #define ACL_ALTER_SYSTEM (1<<13)   /* for configuration parameters */
-#define ACL_MAINTAIN       (1<<14) /* for relations */
-#define N_ACL_RIGHTS   15      /* 1 plus the last 1<
+#define N_ACL_RIGHTS   14      /* 1 plus the last 1<
 #define ACL_NO_RIGHTS  0
 /* Currently, SELECT ... FOR [KEY] UPDATE/SHARE requires UPDATE privileges */
 #define ACL_SELECT_FOR_UPDATE  ACL_UPDATE
index f8e1238fa2cfa1b76c12e2e06645eb78fb464b5a..aba1afa971c82c0ca2f5426027a34559628f742a 100644 (file)
@@ -148,16 +148,15 @@ typedef struct ArrayType Acl;
 #define ACL_CONNECT_CHR            'c'
 #define ACL_SET_CHR                's'
 #define ACL_ALTER_SYSTEM_CHR   'A'
-#define ACL_MAINTAIN_CHR       'm'
 
 /* string holding all privilege code chars, in order by bitmask position */
-#define ACL_ALL_RIGHTS_STR "arwdDxtXUCTcsAm"
+#define ACL_ALL_RIGHTS_STR "arwdDxtXUCTcsA"
 
 /*
  * Bitmasks defining "all rights" for each supported object type
  */
 #define ACL_ALL_RIGHTS_COLUMN      (ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_REFERENCES)
-#define ACL_ALL_RIGHTS_RELATION        (ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_TRUNCATE|ACL_REFERENCES|ACL_TRIGGER|ACL_MAINTAIN)
+#define ACL_ALL_RIGHTS_RELATION        (ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_TRUNCATE|ACL_REFERENCES|ACL_TRIGGER)
 #define ACL_ALL_RIGHTS_SEQUENCE        (ACL_USAGE|ACL_SELECT|ACL_UPDATE)
 #define ACL_ALL_RIGHTS_DATABASE        (ACL_CREATE|ACL_CREATE_TEMP|ACL_CONNECT)
 #define ACL_ALL_RIGHTS_FDW         (ACL_USAGE)
index 7be9e56ef1388cea06ec84d53a9c4617b990aa91..7acb675c97df859b8aee53276e5a958abbac0350 100644 (file)
@@ -3,7 +3,7 @@ Parsed test spec with 2 sessions
 starting permutation: s1_begin s1_lock_parent s2_auth s2_cluster s1_commit s2_reset
 step s1_begin: BEGIN;
 step s1_lock_parent: LOCK cluster_part_tab IN SHARE UPDATE EXCLUSIVE MODE;
-step s2_auth: SET ROLE regress_cluster_part; SET client_min_messages = ERROR;
+step s2_auth: SET ROLE regress_cluster_part;
 step s2_cluster: CLUSTER cluster_part_tab USING cluster_part_ind; 
 step s1_commit: COMMIT;
 step s2_cluster: <... completed>
@@ -11,7 +11,7 @@ step s2_reset: RESET ROLE;
 
 starting permutation: s1_begin s2_auth s1_lock_parent s2_cluster s1_commit s2_reset
 step s1_begin: BEGIN;
-step s2_auth: SET ROLE regress_cluster_part; SET client_min_messages = ERROR;
+step s2_auth: SET ROLE regress_cluster_part;
 step s1_lock_parent: LOCK cluster_part_tab IN SHARE UPDATE EXCLUSIVE MODE;
 step s2_cluster: CLUSTER cluster_part_tab USING cluster_part_ind; 
 step s1_commit: COMMIT;
@@ -21,14 +21,14 @@ step s2_reset: RESET ROLE;
 starting permutation: s1_begin s1_lock_child s2_auth s2_cluster s1_commit s2_reset
 step s1_begin: BEGIN;
 step s1_lock_child: LOCK cluster_part_tab1 IN SHARE UPDATE EXCLUSIVE MODE;
-step s2_auth: SET ROLE regress_cluster_part; SET client_min_messages = ERROR;
+step s2_auth: SET ROLE regress_cluster_part;
 step s2_cluster: CLUSTER cluster_part_tab USING cluster_part_ind;
 step s1_commit: COMMIT;
 step s2_reset: RESET ROLE;
 
 starting permutation: s1_begin s2_auth s1_lock_child s2_cluster s1_commit s2_reset
 step s1_begin: BEGIN;
-step s2_auth: SET ROLE regress_cluster_part; SET client_min_messages = ERROR;
+step s2_auth: SET ROLE regress_cluster_part;
 step s1_lock_child: LOCK cluster_part_tab1 IN SHARE UPDATE EXCLUSIVE MODE;
 step s2_cluster: CLUSTER cluster_part_tab USING cluster_part_ind;
 step s1_commit: COMMIT;
index 4d38a7f49a1477f6ee8e65f2f963ab63fc3b4d8d..5091f684a97e8807f52c98a20b3fb307a9020d23 100644 (file)
@@ -23,7 +23,7 @@ step s1_lock_child     { LOCK cluster_part_tab1 IN SHARE UPDATE EXCLUSIVE MODE;
 step s1_commit         { COMMIT; }
 
 session s2
-step s2_auth           { SET ROLE regress_cluster_part; SET client_min_messages = ERROR; }
+step s2_auth           { SET ROLE regress_cluster_part; }
 step s2_cluster        { CLUSTER cluster_part_tab USING cluster_part_ind; }
 step s2_reset          { RESET ROLE; }
 
index 843f65b448be3fedbf53a099df97587a5431759a..a241d2ceffd9b41b212be93d5c3bce50cb469313 100644 (file)
@@ -274,17 +274,6 @@ sub adjust_old_dumpfile
        $dump = _mash_view_qualifiers($dump);
    }
 
-   if ($old_version >= 14 && $old_version < 16)
-   {
-       # Fix up some privilege-set discrepancies.
-       $dump =~
-         s {^REVOKE SELECT,INSERT,REFERENCES,DELETE,TRIGGER,TRUNCATE,UPDATE ON TABLE}
-           {REVOKE ALL ON TABLE}mg;
-       $dump =~
-         s {^(GRANT SELECT,INSERT,REFERENCES,TRIGGER,TRUNCATE),UPDATE ON TABLE}
-           {$1,MAINTAIN,UPDATE ON TABLE}mg;
-   }
-
    if ($old_version < 14)
    {
        # Remove mentions of extended hash functions.
index a13aafff0b69e992a0e8703163541b9b2f3d90b6..542c2e098c5b1d32826cada761f3dc584cfe20f3 100644 (file)
@@ -352,9 +352,7 @@ INSERT INTO clstr_3 VALUES (1);
 -- this user can only cluster clstr_1 and clstr_3, but the latter
 -- has not been clustered
 SET SESSION AUTHORIZATION regress_clstr_user;
-SET client_min_messages = ERROR;  -- order of "skipping" warnings may vary
 CLUSTER;
-RESET client_min_messages;
 SELECT * FROM clstr_1 UNION ALL
   SELECT * FROM clstr_2 UNION ALL
   SELECT * FROM clstr_3;
@@ -502,17 +500,12 @@ CREATE TABLE ptnowner1 PARTITION OF ptnowner FOR VALUES IN (1);
 CREATE ROLE regress_ptnowner;
 CREATE TABLE ptnowner2 PARTITION OF ptnowner FOR VALUES IN (2);
 ALTER TABLE ptnowner1 OWNER TO regress_ptnowner;
-SET SESSION AUTHORIZATION regress_ptnowner;
-CLUSTER ptnowner USING ptnowner_i_idx;
-ERROR:  permission denied for table ptnowner
-RESET SESSION AUTHORIZATION;
 ALTER TABLE ptnowner OWNER TO regress_ptnowner;
 CREATE TEMP TABLE ptnowner_oldnodes AS
   SELECT oid, relname, relfilenode FROM pg_partition_tree('ptnowner') AS tree
   JOIN pg_class AS c ON c.oid=tree.relid;
 SET SESSION AUTHORIZATION regress_ptnowner;
 CLUSTER ptnowner USING ptnowner_i_idx;
-WARNING:  permission denied to cluster "ptnowner2", skipping it
 RESET SESSION AUTHORIZATION;
 SELECT a.relname, a.relfilenode=b.relfilenode FROM pg_class a
   JOIN ptnowner_oldnodes b USING (oid) ORDER BY a.relname COLLATE "C";
index 1473bc3175fa75254405b8f0f61a8b3856ceda08..acfd9d1f4f7cfc7bec71f456b5f2c4ed852bea68 100644 (file)
@@ -2831,9 +2831,9 @@ RESET ROLE;
 GRANT USAGE ON SCHEMA pg_toast TO regress_reindexuser;
 SET SESSION ROLE regress_reindexuser;
 REINDEX TABLE pg_toast.pg_toast_1260;
-ERROR:  permission denied for table pg_toast_1260
+ERROR:  must be owner of table pg_toast_1260
 REINDEX INDEX pg_toast.pg_toast_1260_index;
-ERROR:  permission denied for index pg_toast_1260_index
+ERROR:  must be owner of index pg_toast_1260_index
 -- Clean up
 RESET ROLE;
 REVOKE USAGE ON SCHEMA pg_toast FROM regress_reindexuser;
index 2b96720e29af12bb338ece2e521838c7a51afd1d..6d9498cdd1844ab15bc3fdaba85cdfb347e3c4f3 100644 (file)
@@ -19,7 +19,7 @@ DETAIL:  privileges for table deptest
 REVOKE SELECT ON deptest FROM GROUP regress_dep_group;
 DROP GROUP regress_dep_group;
 -- can't drop the user if we revoke the privileges partially
-REVOKE SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, MAINTAIN ON deptest FROM regress_dep_user;
+REVOKE SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES ON deptest FROM regress_dep_user;
 DROP USER regress_dep_user;
 ERROR:  role "regress_dep_user" cannot be dropped because some objects depend on it
 DETAIL:  privileges for table deptest
@@ -67,21 +67,21 @@ CREATE TABLE deptest (a serial primary key, b text);
 GRANT ALL ON deptest1 TO regress_dep_user2;
 RESET SESSION AUTHORIZATION;
 \z deptest1
-                                                Access privileges
- Schema |   Name   | Type  |                  Access privileges                   | Column privileges | Policies 
---------+----------+-------+------------------------------------------------------+-------------------+----------
- public | deptest1 | table | regress_dep_user0=arwdDxtm/regress_dep_user0        +|                   | 
-        |          |       | regress_dep_user1=a*r*w*d*D*x*t*m*/regress_dep_user0+|                   | 
-        |          |       | regress_dep_user2=arwdDxtm/regress_dep_user1         |                   | 
+                                               Access privileges
+ Schema |   Name   | Type  |                 Access privileges                  | Column privileges | Policies 
+--------+----------+-------+----------------------------------------------------+-------------------+----------
+ public | deptest1 | table | regress_dep_user0=arwdDxt/regress_dep_user0       +|                   | 
+        |          |       | regress_dep_user1=a*r*w*d*D*x*t*/regress_dep_user0+|                   | 
+        |          |       | regress_dep_user2=arwdDxt/regress_dep_user1        |                   | 
 (1 row)
 
 DROP OWNED BY regress_dep_user1;
 -- all grants revoked
 \z deptest1
-                                            Access privileges
- Schema |   Name   | Type  |              Access privileges               | Column privileges | Policies 
---------+----------+-------+----------------------------------------------+-------------------+----------
- public | deptest1 | table | regress_dep_user0=arwdDxtm/regress_dep_user0 |                   | 
+                                           Access privileges
+ Schema |   Name   | Type  |              Access privileges              | Column privileges | Policies 
+--------+----------+-------+---------------------------------------------+-------------------+----------
+ public | deptest1 | table | regress_dep_user0=arwdDxt/regress_dep_user0 |                   | 
 (1 row)
 
 -- table was dropped
index 3e4dfcc2ec2ec57e03d340167c37eb75b64952b1..c1e610e62f3b175f006fc6bcdae7d0abe0fb59e5 100644 (file)
@@ -2278,9 +2278,9 @@ SELECT pg_input_is_valid('regress_priv_user1=rY', 'aclitem');
 (1 row)
 
 SELECT * FROM pg_input_error_info('regress_priv_user1=rY', 'aclitem');
-                         message                          | detail | hint | sql_error_code 
-----------------------------------------------------------+--------+------+----------------
- invalid mode character: must be one of "arwdDxtXUCTcsAm" |        |      | 22P02
+                         message                         | detail | hint | sql_error_code 
+---------------------------------------------------------+--------+------+----------------
+ invalid mode character: must be one of "arwdDxtXUCTcsA" |        |      | 22P02
 (1 row)
 
 --
@@ -2621,38 +2621,38 @@ set session role regress_priv_user4;
 grant select on dep_priv_test to regress_priv_user5;
 \dp dep_priv_test
                                                Access privileges
- Schema |     Name      | Type  |               Access privileges                | Column privileges | Policies 
---------+---------------+-------+------------------------------------------------+-------------------+----------
- public | dep_priv_test | table | regress_priv_user1=arwdDxtm/regress_priv_user1+|                   | 
-        |               |       | regress_priv_user2=r*/regress_priv_user1      +|                   | 
-        |               |       | regress_priv_user3=r*/regress_priv_user1      +|                   | 
-        |               |       | regress_priv_user4=r*/regress_priv_user2      +|                   | 
-        |               |       | regress_priv_user4=r*/regress_priv_user3      +|                   | 
-        |               |       | regress_priv_user5=r/regress_priv_user4        |                   | 
+ Schema |     Name      | Type  |               Access privileges               | Column privileges | Policies 
+--------+---------------+-------+-----------------------------------------------+-------------------+----------
+ public | dep_priv_test | table | regress_priv_user1=arwdDxt/regress_priv_user1+|                   | 
+        |               |       | regress_priv_user2=r*/regress_priv_user1     +|                   | 
+        |               |       | regress_priv_user3=r*/regress_priv_user1     +|                   | 
+        |               |       | regress_priv_user4=r*/regress_priv_user2     +|                   | 
+        |               |       | regress_priv_user4=r*/regress_priv_user3     +|                   | 
+        |               |       | regress_priv_user5=r/regress_priv_user4       |                   | 
 (1 row)
 
 set session role regress_priv_user2;
 revoke select on dep_priv_test from regress_priv_user4 cascade;
 \dp dep_priv_test
                                                Access privileges
- Schema |     Name      | Type  |               Access privileges                | Column privileges | Policies 
---------+---------------+-------+------------------------------------------------+-------------------+----------
- public | dep_priv_test | table | regress_priv_user1=arwdDxtm/regress_priv_user1+|                   | 
-        |               |       | regress_priv_user2=r*/regress_priv_user1      +|                   | 
-        |               |       | regress_priv_user3=r*/regress_priv_user1      +|                   | 
-        |               |       | regress_priv_user4=r*/regress_priv_user3      +|                   | 
-        |               |       | regress_priv_user5=r/regress_priv_user4        |                   | 
+ Schema |     Name      | Type  |               Access privileges               | Column privileges | Policies 
+--------+---------------+-------+-----------------------------------------------+-------------------+----------
+ public | dep_priv_test | table | regress_priv_user1=arwdDxt/regress_priv_user1+|                   | 
+        |               |       | regress_priv_user2=r*/regress_priv_user1     +|                   | 
+        |               |       | regress_priv_user3=r*/regress_priv_user1     +|                   | 
+        |               |       | regress_priv_user4=r*/regress_priv_user3     +|                   | 
+        |               |       | regress_priv_user5=r/regress_priv_user4       |                   | 
 (1 row)
 
 set session role regress_priv_user3;
 revoke select on dep_priv_test from regress_priv_user4 cascade;
 \dp dep_priv_test
                                                Access privileges
- Schema |     Name      | Type  |               Access privileges                | Column privileges | Policies 
---------+---------------+-------+------------------------------------------------+-------------------+----------
- public | dep_priv_test | table | regress_priv_user1=arwdDxtm/regress_priv_user1+|                   | 
-        |               |       | regress_priv_user2=r*/regress_priv_user1      +|                   | 
-        |               |       | regress_priv_user3=r*/regress_priv_user1       |                   | 
+ Schema |     Name      | Type  |               Access privileges               | Column privileges | Policies 
+--------+---------------+-------+-----------------------------------------------+-------------------+----------
+ public | dep_priv_test | table | regress_priv_user1=arwdDxt/regress_priv_user1+|                   | 
+        |               |       | regress_priv_user2=r*/regress_priv_user1     +|                   | 
+        |               |       | regress_priv_user3=r*/regress_priv_user1      |                   | 
 (1 row)
 
 set session role regress_priv_user1;
@@ -2782,20 +2782,6 @@ LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should pass
 COMMIT;
 \c
 REVOKE TRUNCATE ON lock_table FROM regress_locktable_user;
--- LOCK TABLE and MAINTAIN permission
-GRANT MAINTAIN ON lock_table TO regress_locktable_user;
-SET SESSION AUTHORIZATION regress_locktable_user;
-BEGIN;
-LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should pass
-ROLLBACK;
-BEGIN;
-LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should pass
-COMMIT;
-BEGIN;
-LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should pass
-COMMIT;
-\c
-REVOKE MAINTAIN ON lock_table FROM regress_locktable_user;
 -- clean up
 DROP TABLE lock_table;
 DROP USER regress_locktable_user;
@@ -2909,59 +2895,3 @@ DROP SCHEMA regress_roleoption;
 DROP ROLE regress_roleoption_protagonist;
 DROP ROLE regress_roleoption_donor;
 DROP ROLE regress_roleoption_recipient;
--- MAINTAIN
-CREATE ROLE regress_no_maintain;
-CREATE ROLE regress_maintain;
-CREATE ROLE regress_maintain_all IN ROLE pg_maintain;
-CREATE TABLE maintain_test (a INT);
-CREATE INDEX ON maintain_test (a);
-GRANT MAINTAIN ON maintain_test TO regress_maintain;
-CREATE MATERIALIZED VIEW refresh_test AS SELECT 1;
-GRANT MAINTAIN ON refresh_test TO regress_maintain;
-CREATE SCHEMA reindex_test;
--- negative tests; should fail
-SET ROLE regress_no_maintain;
-VACUUM maintain_test;
-WARNING:  permission denied to vacuum "maintain_test", skipping it
-ANALYZE maintain_test;
-WARNING:  permission denied to analyze "maintain_test", skipping it
-VACUUM (ANALYZE) maintain_test;
-WARNING:  permission denied to vacuum "maintain_test", skipping it
-CLUSTER maintain_test USING maintain_test_a_idx;
-ERROR:  permission denied for table maintain_test
-REFRESH MATERIALIZED VIEW refresh_test;
-ERROR:  permission denied for table refresh_test
-REINDEX TABLE maintain_test;
-ERROR:  permission denied for table maintain_test
-REINDEX INDEX maintain_test_a_idx;
-ERROR:  permission denied for index maintain_test_a_idx
-REINDEX SCHEMA reindex_test;
-ERROR:  must be owner of schema reindex_test
-RESET ROLE;
-SET ROLE regress_maintain;
-VACUUM maintain_test;
-ANALYZE maintain_test;
-VACUUM (ANALYZE) maintain_test;
-CLUSTER maintain_test USING maintain_test_a_idx;
-REFRESH MATERIALIZED VIEW refresh_test;
-REINDEX TABLE maintain_test;
-REINDEX INDEX maintain_test_a_idx;
-REINDEX SCHEMA reindex_test;
-ERROR:  must be owner of schema reindex_test
-RESET ROLE;
-SET ROLE regress_maintain_all;
-VACUUM maintain_test;
-ANALYZE maintain_test;
-VACUUM (ANALYZE) maintain_test;
-CLUSTER maintain_test USING maintain_test_a_idx;
-REFRESH MATERIALIZED VIEW refresh_test;
-REINDEX TABLE maintain_test;
-REINDEX INDEX maintain_test_a_idx;
-REINDEX SCHEMA reindex_test;
-RESET ROLE;
-DROP TABLE maintain_test;
-DROP MATERIALIZED VIEW refresh_test;
-DROP SCHEMA reindex_test;
-DROP ROLE regress_no_maintain;
-DROP ROLE regress_maintain;
-DROP ROLE regress_maintain_all;
index e27834642082a19d1cba7634b22f2e540a4abc36..4e54976618466313d7f7acf8789bffd4bdf27229 100644 (file)
@@ -93,23 +93,23 @@ CREATE POLICY p2r ON document AS RESTRICTIVE TO regress_rls_dave
 CREATE POLICY p1r ON document AS RESTRICTIVE TO regress_rls_dave
     USING (cid <> 44);
 \dp
-                                                                   Access privileges
-       Schema       |   Name   | Type  |              Access privileges               | Column privileges |                  Policies                  
---------------------+----------+-------+----------------------------------------------+-------------------+--------------------------------------------
- regress_rls_schema | category | table | regress_rls_alice=arwdDxtm/regress_rls_alice+|                   | 
-                    |          |       | =arwdDxtm/regress_rls_alice                  |                   | 
- regress_rls_schema | document | table | regress_rls_alice=arwdDxtm/regress_rls_alice+|                   | p1:                                       +
-                    |          |       | =arwdDxtm/regress_rls_alice                  |                   |   (u): (dlevel <= ( SELECT uaccount.seclv +
-                    |          |       |                                              |                   |    FROM uaccount                          +
-                    |          |       |                                              |                   |   WHERE (uaccount.pguser = CURRENT_USER)))+
-                    |          |       |                                              |                   | p2r (RESTRICTIVE):                        +
-                    |          |       |                                              |                   |   (u): ((cid <> 44) AND (cid < 50))       +
-                    |          |       |                                              |                   |   to: regress_rls_dave                    +
-                    |          |       |                                              |                   | p1r (RESTRICTIVE):                        +
-                    |          |       |                                              |                   |   (u): (cid <> 44)                        +
-                    |          |       |                                              |                   |   to: regress_rls_dave
- regress_rls_schema | uaccount | table | regress_rls_alice=arwdDxtm/regress_rls_alice+|                   | 
-                    |          |       | =r/regress_rls_alice                         |                   | 
+                                                                  Access privileges
+       Schema       |   Name   | Type  |              Access privileges              | Column privileges |                  Policies                  
+--------------------+----------+-------+---------------------------------------------+-------------------+--------------------------------------------
+ regress_rls_schema | category | table | regress_rls_alice=arwdDxt/regress_rls_alice+|                   | 
+                    |          |       | =arwdDxt/regress_rls_alice                  |                   | 
+ regress_rls_schema | document | table | regress_rls_alice=arwdDxt/regress_rls_alice+|                   | p1:                                       +
+                    |          |       | =arwdDxt/regress_rls_alice                  |                   |   (u): (dlevel <= ( SELECT uaccount.seclv +
+                    |          |       |                                             |                   |    FROM uaccount                          +
+                    |          |       |                                             |                   |   WHERE (uaccount.pguser = CURRENT_USER)))+
+                    |          |       |                                             |                   | p2r (RESTRICTIVE):                        +
+                    |          |       |                                             |                   |   (u): ((cid <> 44) AND (cid < 50))       +
+                    |          |       |                                             |                   |   to: regress_rls_dave                    +
+                    |          |       |                                             |                   | p1r (RESTRICTIVE):                        +
+                    |          |       |                                             |                   |   (u): (cid <> 44)                        +
+                    |          |       |                                             |                   |   to: regress_rls_dave
+ regress_rls_schema | uaccount | table | regress_rls_alice=arwdDxt/regress_rls_alice+|                   | 
+                    |          |       | =r/regress_rls_alice                        |                   | 
 (3 rows)
 
 \d document
index b7115f861044d7650892b8f5c1ba33a7d3c3084b..6cb9c926c06eb4e9f7eff611b3a73ac778066731 100644 (file)
@@ -145,9 +145,7 @@ INSERT INTO clstr_3 VALUES (1);
 -- this user can only cluster clstr_1 and clstr_3, but the latter
 -- has not been clustered
 SET SESSION AUTHORIZATION regress_clstr_user;
-SET client_min_messages = ERROR;  -- order of "skipping" warnings may vary
 CLUSTER;
-RESET client_min_messages;
 SELECT * FROM clstr_1 UNION ALL
   SELECT * FROM clstr_2 UNION ALL
   SELECT * FROM clstr_3;
@@ -238,9 +236,6 @@ CREATE TABLE ptnowner1 PARTITION OF ptnowner FOR VALUES IN (1);
 CREATE ROLE regress_ptnowner;
 CREATE TABLE ptnowner2 PARTITION OF ptnowner FOR VALUES IN (2);
 ALTER TABLE ptnowner1 OWNER TO regress_ptnowner;
-SET SESSION AUTHORIZATION regress_ptnowner;
-CLUSTER ptnowner USING ptnowner_i_idx;
-RESET SESSION AUTHORIZATION;
 ALTER TABLE ptnowner OWNER TO regress_ptnowner;
 CREATE TEMP TABLE ptnowner_oldnodes AS
   SELECT oid, relname, relfilenode FROM pg_partition_tree('ptnowner') AS tree
index 8d74ed7122c249494d677f3acbc8ca97892d6517..2559c62d0b89a0c80fe9b7bcd196404c04ce9f34 100644 (file)
@@ -21,7 +21,7 @@ REVOKE SELECT ON deptest FROM GROUP regress_dep_group;
 DROP GROUP regress_dep_group;
 
 -- can't drop the user if we revoke the privileges partially
-REVOKE SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, MAINTAIN ON deptest FROM regress_dep_user;
+REVOKE SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES ON deptest FROM regress_dep_user;
 DROP USER regress_dep_user;
 
 -- now we are OK to drop him
index 134809e8cc559c902bebd1177030f428e2366d1f..bf0035d96d253907310d09199dd7416c7a55e4c9 100644 (file)
@@ -1778,21 +1778,6 @@ COMMIT;
 \c
 REVOKE TRUNCATE ON lock_table FROM regress_locktable_user;
 
--- LOCK TABLE and MAINTAIN permission
-GRANT MAINTAIN ON lock_table TO regress_locktable_user;
-SET SESSION AUTHORIZATION regress_locktable_user;
-BEGIN;
-LOCK TABLE lock_table IN ACCESS SHARE MODE; -- should pass
-ROLLBACK;
-BEGIN;
-LOCK TABLE lock_table IN ROW EXCLUSIVE MODE; -- should pass
-COMMIT;
-BEGIN;
-LOCK TABLE lock_table IN ACCESS EXCLUSIVE MODE; -- should pass
-COMMIT;
-\c
-REVOKE MAINTAIN ON lock_table FROM regress_locktable_user;
-
 -- clean up
 DROP TABLE lock_table;
 DROP USER regress_locktable_user;
@@ -1876,56 +1861,3 @@ DROP SCHEMA regress_roleoption;
 DROP ROLE regress_roleoption_protagonist;
 DROP ROLE regress_roleoption_donor;
 DROP ROLE regress_roleoption_recipient;
-
--- MAINTAIN
-CREATE ROLE regress_no_maintain;
-CREATE ROLE regress_maintain;
-CREATE ROLE regress_maintain_all IN ROLE pg_maintain;
-
-CREATE TABLE maintain_test (a INT);
-CREATE INDEX ON maintain_test (a);
-GRANT MAINTAIN ON maintain_test TO regress_maintain;
-CREATE MATERIALIZED VIEW refresh_test AS SELECT 1;
-GRANT MAINTAIN ON refresh_test TO regress_maintain;
-CREATE SCHEMA reindex_test;
-
--- negative tests; should fail
-SET ROLE regress_no_maintain;
-VACUUM maintain_test;
-ANALYZE maintain_test;
-VACUUM (ANALYZE) maintain_test;
-CLUSTER maintain_test USING maintain_test_a_idx;
-REFRESH MATERIALIZED VIEW refresh_test;
-REINDEX TABLE maintain_test;
-REINDEX INDEX maintain_test_a_idx;
-REINDEX SCHEMA reindex_test;
-RESET ROLE;
-
-SET ROLE regress_maintain;
-VACUUM maintain_test;
-ANALYZE maintain_test;
-VACUUM (ANALYZE) maintain_test;
-CLUSTER maintain_test USING maintain_test_a_idx;
-REFRESH MATERIALIZED VIEW refresh_test;
-REINDEX TABLE maintain_test;
-REINDEX INDEX maintain_test_a_idx;
-REINDEX SCHEMA reindex_test;
-RESET ROLE;
-
-SET ROLE regress_maintain_all;
-VACUUM maintain_test;
-ANALYZE maintain_test;
-VACUUM (ANALYZE) maintain_test;
-CLUSTER maintain_test USING maintain_test_a_idx;
-REFRESH MATERIALIZED VIEW refresh_test;
-REINDEX TABLE maintain_test;
-REINDEX INDEX maintain_test_a_idx;
-REINDEX SCHEMA reindex_test;
-RESET ROLE;
-
-DROP TABLE maintain_test;
-DROP MATERIALIZED VIEW refresh_test;
-DROP SCHEMA reindex_test;
-DROP ROLE regress_no_maintain;
-DROP ROLE regress_maintain;
-DROP ROLE regress_maintain_all;