diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index e32f8253d0..4317995965 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -1718,8 +1718,8 @@ ALTER TABLE products RENAME TO items; INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER, CREATE, CONNECT, TEMPORARY, - EXECUTE, USAGE, SET, - ALTER SYSTEM, and MAINTAIN. + EXECUTE, USAGE, SET + 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 VACUUM, ANALYZE, - CLUSTER, REFRESH 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) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 5a47ce4343..0b62e0c828 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -23545,7 +23545,7 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute'); are SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, - TRIGGER, and MAINTAIN. + and TRIGGER. diff --git a/doc/src/sgml/ref/alter_default_privileges.sgml b/doc/src/sgml/ref/alter_default_privileges.sgml index a33461fbc2..f1d54f5aa3 100644 --- a/doc/src/sgml/ref/alter_default_privileges.sgml +++ b/doc/src/sgml/ref/alter_default_privileges.sgml @@ -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 } [, ...] diff --git a/doc/src/sgml/ref/analyze.sgml b/doc/src/sgml/ref/analyze.sgml index 954491b5df..aa3e9e1c5f 100644 --- a/doc/src/sgml/ref/analyze.sgml +++ b/doc/src/sgml/ref/analyze.sgml @@ -182,9 +182,11 @@ ANALYZE [ VERBOSE ] [ table_and_columnsNotes - 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. diff --git a/doc/src/sgml/ref/cluster.sgml b/doc/src/sgml/ref/cluster.sgml index 06f3d269e6..0ed29a5c6d 100644 --- a/doc/src/sgml/ref/cluster.sgml +++ b/doc/src/sgml/ref/cluster.sgml @@ -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 diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml index 35bf0332c8..1ae5770fbb 100644 --- a/doc/src/sgml/ref/grant.sgml +++ b/doc/src/sgml/ref/grant.sgml @@ -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 . diff --git a/doc/src/sgml/ref/lock.sgml b/doc/src/sgml/ref/lock.sgml index 070855da18..6ce2518de7 100644 --- a/doc/src/sgml/ref/lock.sgml +++ b/doc/src/sgml/ref/lock.sgml @@ -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 UPDATE, DELETE, or TRUNCATE privileges on the table, any lockmode is permitted. If the user has diff --git a/doc/src/sgml/ref/refresh_materialized_view.sgml b/doc/src/sgml/ref/refresh_materialized_view.sgml index 19737668cd..675d6090f3 100644 --- a/doc/src/sgml/ref/refresh_materialized_view.sgml +++ b/doc/src/sgml/ref/refresh_materialized_view.sgml @@ -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 diff --git a/doc/src/sgml/ref/reindex.sgml b/doc/src/sgml/ref/reindex.sgml index bef3486843..21e2e91d89 100644 --- a/doc/src/sgml/ref/reindex.sgml +++ b/doc/src/sgml/ref/reindex.sgml @@ -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 DATABASE, REINDEX 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 DATABASE, REINDEX 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. diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml index 8df492281a..2db66bbf37 100644 --- a/doc/src/sgml/ref/revoke.sgml +++ b/doc/src/sgml/ref/revoke.sgml @@ -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 [, ...] } diff --git a/doc/src/sgml/ref/vacuum.sgml b/doc/src/sgml/ref/vacuum.sgml index c42bbea9e2..65c03bf829 100644 --- a/doc/src/sgml/ref/vacuum.sgml +++ b/doc/src/sgml/ref/vacuum.sgml @@ -444,9 +444,11 @@ VACUUM [ FULL ] [ FREEZE ] [ VERBOSE ] [ ANALYZE ] [ 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 diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index bc2ad773c9..d1f5dcd8be 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -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; } diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c index 9c8413eef2..bfd981aa3f 100644 --- a/src/backend/commands/analyze.c +++ b/src/backend/commands/analyze.c @@ -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; diff --git a/src/backend/commands/cluster.c b/src/backend/commands/cluster.c index 03b24ab90f..92c465c05b 100644 --- a/src/backend/commands/cluster.c +++ b/src/backend/commands/cluster.c @@ -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; -} diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index 403f5fc143..02250ae74b 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -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; /* diff --git a/src/backend/commands/lockcmds.c b/src/backend/commands/lockcmds.c index 92662cbbc8..40ef4ede26 100644 --- a/src/backend/commands/lockcmds.c +++ b/src/backend/commands/lockcmds.c @@ -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) diff --git a/src/backend/commands/matview.c b/src/backend/commands/matview.c index f9a3bdfc3a..ac2e74fa3f 100644 --- a/src/backend/commands/matview.c +++ b/src/backend/commands/matview.c @@ -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; diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index fce5e6f220..5316f58308 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -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); } /* diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c index 7fe6a54c06..57ca41add2 100644 --- a/src/backend/commands/vacuum.c +++ b/src/backend/commands/vacuum.c @@ -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). + * 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 (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 - *---------- - */ - 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); } diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index c660fd3e70..883e09393a 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -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} diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c index 0ea96346cb..d2851cf568 100644 --- a/src/bin/pg_dump/dumputils.c +++ b/src/bin/pg_dump/dumputils.c @@ -463,7 +463,6 @@ do { \ CONVERT_PRIV('d', "DELETE"); CONVERT_PRIV('t', "TRIGGER"); CONVERT_PRIV('D', "TRUNCATE"); - CONVERT_PRIV('m', "MAINTAIN"); } } diff --git a/src/bin/pg_dump/t/002_pg_dump.pl b/src/bin/pg_dump/t/002_pg_dump.pl index 63bb4689d4..d42243bf71 100644 --- a/src/bin/pg_dump/t/002_pg_dump.pl +++ b/src/bin/pg_dump/t/002_pg_dump.pl @@ -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, }, diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 935bb9bd95..e9fddd91eb 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -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"); diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index b0c557a828..83f3a7c2ec 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -57,6 +57,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202307031 +#define CATALOG_VERSION_NO 202307072 #endif diff --git a/src/include/catalog/pg_authid.dat b/src/include/catalog/pg_authid.dat index 1d7e00b2fd..6b4a0aaaad 100644 --- a/src/include/catalog/pg_authid.dat +++ b/src/include/catalog/pg_authid.dat @@ -84,11 +84,6 @@ 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', diff --git a/src/include/commands/tablecmds.h b/src/include/commands/tablecmds.h index 250d89ff88..16b6126669 100644 --- a/src/include/commands/tablecmds.h +++ b/src/include/commands/tablecmds.h @@ -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); diff --git a/src/include/commands/vacuum.h b/src/include/commands/vacuum.h index b027fb2c67..4af02940c5 100644 --- a/src/include/commands/vacuum.h +++ b/src/include/commands/vacuum.h @@ -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); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 88b03cc472..efb5c3e098 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -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< 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; diff --git a/src/test/isolation/specs/cluster-conflict-partition.spec b/src/test/isolation/specs/cluster-conflict-partition.spec index 4d38a7f49a..5091f684a9 100644 --- a/src/test/isolation/specs/cluster-conflict-partition.spec +++ b/src/test/isolation/specs/cluster-conflict-partition.spec @@ -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; } diff --git a/src/test/perl/PostgreSQL/Test/AdjustUpgrade.pm b/src/test/perl/PostgreSQL/Test/AdjustUpgrade.pm index 843f65b448..a241d2ceff 100644 --- a/src/test/perl/PostgreSQL/Test/AdjustUpgrade.pm +++ b/src/test/perl/PostgreSQL/Test/AdjustUpgrade.pm @@ -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. diff --git a/src/test/regress/expected/cluster.out b/src/test/regress/expected/cluster.out index a13aafff0b..542c2e098c 100644 --- a/src/test/regress/expected/cluster.out +++ b/src/test/regress/expected/cluster.out @@ -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"; diff --git a/src/test/regress/expected/create_index.out b/src/test/regress/expected/create_index.out index 1473bc3175..acfd9d1f4f 100644 --- a/src/test/regress/expected/create_index.out +++ b/src/test/regress/expected/create_index.out @@ -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; diff --git a/src/test/regress/expected/dependency.out b/src/test/regress/expected/dependency.out index 2b96720e29..6d9498cdd1 100644 --- a/src/test/regress/expected/dependency.out +++ b/src/test/regress/expected/dependency.out @@ -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 diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out index 3e4dfcc2ec..c1e610e62f 100644 --- a/src/test/regress/expected/privileges.out +++ b/src/test/regress/expected/privileges.out @@ -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; diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out index e278346420..4e54976618 100644 --- a/src/test/regress/expected/rowsecurity.out +++ b/src/test/regress/expected/rowsecurity.out @@ -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 diff --git a/src/test/regress/sql/cluster.sql b/src/test/regress/sql/cluster.sql index b7115f8610..6cb9c926c0 100644 --- a/src/test/regress/sql/cluster.sql +++ b/src/test/regress/sql/cluster.sql @@ -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 diff --git a/src/test/regress/sql/dependency.sql b/src/test/regress/sql/dependency.sql index 8d74ed7122..2559c62d0b 100644 --- a/src/test/regress/sql/dependency.sql +++ b/src/test/regress/sql/dependency.sql @@ -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 diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql index 134809e8cc..bf0035d96d 100644 --- a/src/test/regress/sql/privileges.sql +++ b/src/test/regress/sql/privileges.sql @@ -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;