From 4789e9880148660c7126aef4fbaf5563be6ff167 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Sat, 21 Jan 2006 02:16:21 +0000 Subject: [PATCH] Add GRANT ON SEQUENCE syntax to support sequence-only permissions. Continue to support GRANT ON [TABLE] for sequences for backward compatibility; issue warning for invalid sequence permissions. [Backward compatibility warning message.] Add USAGE permission for sequences that allows only currval() and nextval(), not setval(). Mention object name in grant/revoke warnings because of possible multi-object operations. --- doc/src/sgml/ref/grant.sgml | 13 +++- doc/src/sgml/ref/revoke.sgml | 9 ++- src/backend/catalog/aclchk.c | 125 ++++++++++++++++++++++++++----- src/backend/catalog/pg_shdepend.c | 21 +++++- src/backend/commands/sequence.c | 11 ++- src/backend/parser/gram.y | 9 ++- src/backend/utils/adt/acl.c | 6 +- src/bin/pg_dump/dumputils.c | 44 ++++++----- src/bin/pg_dump/pg_backup_archiver.c | 8 +- src/bin/pg_dump/pg_dump.c | 5 +- src/include/nodes/parsenodes.h | 5 +- src/include/utils/acl.h | 4 +- src/test/regress/expected/privileges.out | 6 +- 13 files changed, 207 insertions(+), 59 deletions(-) diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml index bb9571abd8..e5ea4bb144 100644 --- a/doc/src/sgml/ref/grant.sgml +++ b/doc/src/sgml/ref/grant.sgml @@ -1,5 +1,5 @@ @@ -25,6 +25,11 @@ GRANT { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } ON [ TABLE ] tablename [, ...] TO { username | GROUP groupname | PUBLIC } [, ...] [ WITH GRANT OPTION ] +GRANT { { USAGE | SELECT | UPDATE } + [,...] | ALL [ PRIVILEGES ] } + ON SEQUENCE sequencename [, ...] + TO { username | GROUP groupname | PUBLIC } [, ...] [ WITH GRANT OPTION ] + GRANT { { CREATE | TEMPORARY | TEMP } [,...] | ALL [ PRIVILEGES ] } ON DATABASE dbname [, ...] TO { username | GROUP groupname | PUBLIC } [, ...] [ WITH GRANT OPTION ] @@ -260,6 +265,10 @@ GRANT role [, ...] also met). Essentially this allows the grantee to look up objects within the schema. + + For sequences, this privilege allows the use of the + currval and nextval functions. + @@ -511,7 +520,7 @@ GRANT privileges The RULE privilege, and privileges on - databases, tablespaces, schemas, languages, and sequences are + databases, tablespaces, schemas, and languages are PostgreSQL extensions. diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml index 68c69f8814..f09642a7b5 100644 --- a/doc/src/sgml/ref/revoke.sgml +++ b/doc/src/sgml/ref/revoke.sgml @@ -1,5 +1,5 @@ @@ -28,6 +28,13 @@ REVOKE [ GRANT OPTION FOR ] [ CASCADE | RESTRICT ] REVOKE [ GRANT OPTION FOR ] + { { USAGE | SELECT | UPDATE } + [,...] | ALL [ PRIVILEGES ] } + ON SEQUENCE sequencename [, ...] + FROM { username | GROUP groupname | PUBLIC } [, ...] + [ CASCADE | RESTRICT ] + +REVOKE [ GRANT OPTION FOR ] { { CREATE | TEMPORARY | TEMP } [,...] | ALL [ PRIVILEGES ] } ON DATABASE dbname [, ...] FROM { username | GROUP groupname | PUBLIC } [, ...] diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c index 643d31c199..dbdf523dd5 100644 --- a/src/backend/catalog/aclchk.c +++ b/src/backend/catalog/aclchk.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.123 2005/12/01 02:03:00 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/aclchk.c,v 1.124 2006/01/21 02:16:18 momjian Exp $ * * NOTES * See acl.h. @@ -164,6 +164,9 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs, case ACL_KIND_CLASS: whole_mask = ACL_ALL_RIGHTS_RELATION; break; + case ACL_KIND_SEQUENCE: + whole_mask = ACL_ALL_RIGHTS_SEQUENCE; + break; case ACL_KIND_DATABASE: whole_mask = ACL_ALL_RIGHTS_DATABASE; break; @@ -212,22 +215,22 @@ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs, if (this_privileges == 0) ereport(WARNING, (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), - errmsg("no privileges were granted"))); + errmsg("no privileges were granted for \"%s\"", objname))); else if (!all_privs && this_privileges != privileges) ereport(WARNING, (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED), - errmsg("not all privileges were granted"))); + errmsg("not all privileges were granted for \"%s\"", objname))); } else { if (this_privileges == 0) ereport(WARNING, (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), - errmsg("no privileges could be revoked"))); + errmsg("no privileges could be revoked for \"%s\"", objname))); else if (!all_privs && this_privileges != privileges) ereport(WARNING, (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED), - errmsg("not all privileges could be revoked"))); + errmsg("not all privileges could be revoked for \"%s\"", objname))); } return this_privileges; @@ -282,9 +285,18 @@ ExecuteGrantStmt(GrantStmt *stmt) */ switch (stmt->objtype) { + /* + * Because this might be a sequence, we test both relation + * and sequence bits, and later do a more limited test + * when we know the object type. + */ case ACL_OBJECT_RELATION: - all_privileges = ACL_ALL_RIGHTS_RELATION; - errormsg = _("invalid privilege type %s for table"); + all_privileges = ACL_ALL_RIGHTS_RELATION | ACL_ALL_RIGHTS_SEQUENCE; + errormsg = _("invalid privilege type %s for relation"); + break; + case ACL_OBJECT_SEQUENCE: + all_privileges = ACL_ALL_RIGHTS_SEQUENCE; + errormsg = _("invalid privilege type %s for sequence"); break; case ACL_OBJECT_DATABASE: all_privileges = ACL_ALL_RIGHTS_DATABASE; @@ -327,6 +339,7 @@ ExecuteGrantStmt(GrantStmt *stmt) { istmt.all_privs = false; istmt.privileges = ACL_NO_RIGHTS; + foreach(cell, stmt->privileges) { char *privname = strVal(lfirst(cell)); @@ -356,6 +369,7 @@ ExecGrantStmt_oids(InternalGrant *istmt) switch (istmt->objtype) { case ACL_OBJECT_RELATION: + case ACL_OBJECT_SEQUENCE: ExecGrant_Relation(istmt); break; case ACL_OBJECT_DATABASE: @@ -395,6 +409,7 @@ objectNamesToOids(GrantObjectType objtype, List *objnames) switch (objtype) { case ACL_OBJECT_RELATION: + case ACL_OBJECT_SEQUENCE: foreach(cell, objnames) { Oid relOid; @@ -523,15 +538,15 @@ objectNamesToOids(GrantObjectType objtype, List *objnames) return objects; } +/* + * This processes both sequences and non-sequences. + */ static void ExecGrant_Relation(InternalGrant *istmt) { Relation relation; ListCell *cell; - if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) - istmt->privileges = ACL_ALL_RIGHTS_RELATION; - relation = heap_open(RelationRelationId, RowExclusiveLock); foreach(cell, istmt->objects) @@ -577,6 +592,69 @@ ExecGrant_Relation(InternalGrant *istmt) errmsg("\"%s\" is a composite type", NameStr(pg_class_tuple->relname)))); + /* Used GRANT SEQUENCE on a non-sequence? */ + if (istmt->objtype == ACL_OBJECT_SEQUENCE && + pg_class_tuple->relkind != RELKIND_SEQUENCE) + ereport(ERROR, + (errcode(ERRCODE_WRONG_OBJECT_TYPE), + errmsg("\"%s\" is not a sequence", + NameStr(pg_class_tuple->relname)))); + + /* Adjust the default permissions based on whether it is a sequence */ + if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS) + { + if (pg_class_tuple->relkind == RELKIND_SEQUENCE) + this_privileges = ACL_ALL_RIGHTS_SEQUENCE; + else + this_privileges = ACL_ALL_RIGHTS_RELATION; + } + else + this_privileges = istmt->privileges; + + /* + * The GRANT TABLE syntax can be used for sequences and + * non-sequences, so we have to look at the relkind to + * determine the supported permissions. The OR of + * table and sequence permissions were already checked. + */ + if (istmt->objtype == ACL_OBJECT_RELATION) + { + if (pg_class_tuple->relkind == RELKIND_SEQUENCE) + { + /* + * For backward compatibility, throw just a warning + * for invalid sequence permissions when using the + * non-sequence GRANT syntax is used. + */ + if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_SEQUENCE)) + { + /* + * Mention the object name because the user needs to + * know which operations succeeded. This is required + * because WARNING allows the command to continue. + */ + ereport(WARNING, + (errcode(ERRCODE_INVALID_GRANT_OPERATION), + errmsg("sequence \"%s\" only supports USAGE, SELECT, and UPDATE", + NameStr(pg_class_tuple->relname)))); + this_privileges &= (AclMode) ACL_ALL_RIGHTS_SEQUENCE; + } + } + else + { + if (this_privileges & ~((AclMode) ACL_ALL_RIGHTS_RELATION)) + /* + * USAGE is the only permission supported by sequences + * but not by non-sequences. Don't mention the object + * name because we didn't in the combined TABLE | + * SEQUENCE check. + */ + ereport(ERROR, + (errcode(ERRCODE_INVALID_GRANT_OPERATION), + errmsg("invalid privilege type USAGE for table"))); + } + } + /* * Get owner ID and working copy of existing ACL. If there's no ACL, * substitute the proper default. @@ -585,12 +663,14 @@ ExecGrant_Relation(InternalGrant *istmt) aclDatum = SysCacheGetAttr(RELOID, tuple, Anum_pg_class_relacl, &isNull); if (isNull) - old_acl = acldefault(ACL_OBJECT_RELATION, ownerId); + old_acl = acldefault(pg_class_tuple->relkind == RELKIND_SEQUENCE ? + ACL_OBJECT_SEQUENCE : ACL_OBJECT_RELATION, + ownerId); else old_acl = DatumGetAclPCopy(aclDatum); /* Determine ID to do the grant as, and available grant options */ - select_best_grantor(GetUserId(), istmt->privileges, + select_best_grantor(GetUserId(), this_privileges, old_acl, ownerId, &grantorId, &avail_goptions); @@ -600,8 +680,10 @@ ExecGrant_Relation(InternalGrant *istmt) */ this_privileges = restrict_and_check_grant(istmt->is_grant, avail_goptions, - istmt->all_privs, istmt->privileges, - relOid, grantorId, ACL_KIND_CLASS, + istmt->all_privs, this_privileges, + relOid, grantorId, + pg_class_tuple->relkind == RELKIND_SEQUENCE + ? ACL_KIND_SEQUENCE : ACL_KIND_CLASS, NameStr(pg_class_tuple->relname)); /* @@ -1336,6 +1418,8 @@ static const char *const no_priv_msg[MAX_ACL_KIND] = { /* ACL_KIND_CLASS */ gettext_noop("permission denied for relation %s"), + /* ACL_KIND_SEQUENCE */ + gettext_noop("permission denied for sequence %s"), /* ACL_KIND_DATABASE */ gettext_noop("permission denied for database %s"), /* ACL_KIND_PROC */ @@ -1360,6 +1444,8 @@ static const char *const not_owner_msg[MAX_ACL_KIND] = { /* ACL_KIND_CLASS */ gettext_noop("must be owner of relation %s"), + /* ACL_KIND_SEQUENCE */ + gettext_noop("must be owner of sequence %s"), /* ACL_KIND_DATABASE */ gettext_noop("must be owner of database %s"), /* ACL_KIND_PROC */ @@ -1439,6 +1525,7 @@ pg_aclmask(AclObjectKind objkind, Oid table_oid, Oid roleid, switch (objkind) { case ACL_KIND_CLASS: + case ACL_KIND_SEQUENCE: return pg_class_aclmask(table_oid, roleid, mask, how); case ACL_KIND_DATABASE: return pg_database_aclmask(table_oid, roleid, mask, how); @@ -1500,9 +1587,9 @@ pg_class_aclmask(Oid table_oid, Oid roleid, * * As of 7.4 we have some updatable system views; those shouldn't be * protected in this way. Assume the view rules can take care of - * themselves. + * themselves. ACL_USAGE is if we ever have system sequences. */ - if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE)) && + if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_USAGE)) && IsSystemClass(classForm) && classForm->relkind != RELKIND_VIEW && !has_rolcatupdate(roleid) && @@ -1511,7 +1598,7 @@ pg_class_aclmask(Oid table_oid, Oid roleid, #ifdef ACLDEBUG elog(DEBUG2, "permission denied for system catalog update"); #endif - mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE); + mask &= ~(ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_USAGE); } /* @@ -1536,7 +1623,9 @@ pg_class_aclmask(Oid table_oid, Oid roleid, if (isNull) { /* No ACL, so build default ACL */ - acl = acldefault(ACL_OBJECT_RELATION, ownerId); + acl = acldefault(classForm->relkind == RELKIND_SEQUENCE ? + ACL_OBJECT_SEQUENCE : ACL_OBJECT_RELATION, + ownerId); aclDatum = (Datum) 0; } else diff --git a/src/backend/catalog/pg_shdepend.c b/src/backend/catalog/pg_shdepend.c index faa64c22fc..e57a22858f 100644 --- a/src/backend/catalog/pg_shdepend.c +++ b/src/backend/catalog/pg_shdepend.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.6 2005/12/01 02:03:00 alvherre Exp $ + * $PostgreSQL: pgsql/src/backend/catalog/pg_shdepend.c,v 1.7 2006/01/21 02:16:18 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1133,8 +1133,25 @@ shdepDropOwned(List *roleids, DropBehavior behavior) switch (sdepForm->classid) { case RelationRelationId: - istmt.objtype = ACL_OBJECT_RELATION; + { + /* is it a sequence or non-sequence? */ + Form_pg_class pg_class_tuple; + HeapTuple tuple; + + tuple = SearchSysCache(RELOID, + ObjectIdGetDatum(sdepForm->objid), + 0, 0, 0); + if (!HeapTupleIsValid(tuple)) + elog(ERROR, "cache lookup failed for relation %u", + sdepForm->objid); + pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple); + if (pg_class_tuple->relkind == RELKIND_SEQUENCE) + istmt.objtype = ACL_OBJECT_SEQUENCE; + else + istmt.objtype = ACL_OBJECT_RELATION; + ReleaseSysCache(tuple); break; + } case DatabaseRelationId: istmt.objtype = ACL_OBJECT_DATABASE; break; diff --git a/src/backend/commands/sequence.c b/src/backend/commands/sequence.c index 9c1efe856c..53244cbedc 100644 --- a/src/backend/commands/sequence.c +++ b/src/backend/commands/sequence.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.126 2005/11/22 18:17:09 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/sequence.c,v 1.127 2006/01/21 02:16:18 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -422,7 +422,8 @@ nextval_internal(Oid relid) /* open and AccessShareLock sequence */ init_sequence(relid, &elm, &seqrel); - if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK) + if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_USAGE) != ACLCHECK_OK && + pg_class_aclcheck(elm->relid, GetUserId(), ACL_UPDATE) != ACLCHECK_OK) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for sequence %s", @@ -613,7 +614,8 @@ currval_oid(PG_FUNCTION_ARGS) /* open and AccessShareLock sequence */ init_sequence(relid, &elm, &seqrel); - if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK) + if (pg_class_aclcheck(elm->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK && + pg_class_aclcheck(elm->relid, GetUserId(), ACL_USAGE) != ACLCHECK_OK) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for sequence %s", @@ -657,7 +659,8 @@ lastval(PG_FUNCTION_ARGS) /* nextval() must have already been called for this sequence */ Assert(last_used_seq->increment != 0); - if (pg_class_aclcheck(last_used_seq->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK) + if (pg_class_aclcheck(last_used_seq->relid, GetUserId(), ACL_SELECT) != ACLCHECK_OK && + pg_class_aclcheck(last_used_seq->relid, GetUserId(), ACL_USAGE) != ACLCHECK_OK) ereport(ERROR, (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), errmsg("permission denied for sequence %s", diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index ceb7143ce2..41b22d811c 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11,7 +11,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.521 2005/12/29 04:53:18 neilc Exp $ + * $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.522 2006/01/21 02:16:19 momjian Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -3322,6 +3322,13 @@ privilege_target: n->objs = $2; $$ = n; } + | SEQUENCE qualified_name_list + { + PrivTarget *n = makeNode(PrivTarget); + n->objtype = ACL_OBJECT_SEQUENCE; + n->objs = $2; + $$ = n; + } | FUNCTION function_with_argtypes_list { PrivTarget *n = makeNode(PrivTarget); diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c index 9282c417d0..2232e042a3 100644 --- a/src/backend/utils/adt/acl.c +++ b/src/backend/utils/adt/acl.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.129 2005/11/18 02:38:23 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.130 2006/01/21 02:16:19 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -545,6 +545,10 @@ acldefault(GrantObjectType objtype, Oid ownerId) world_default = ACL_NO_RIGHTS; owner_default = ACL_ALL_RIGHTS_RELATION; break; + case ACL_OBJECT_SEQUENCE: + world_default = ACL_NO_RIGHTS; + owner_default = ACL_ALL_RIGHTS_SEQUENCE; + break; case ACL_OBJECT_DATABASE: world_default = ACL_CREATE_TEMP; /* not NO_RIGHTS! */ owner_default = ACL_ALL_RIGHTS_DATABASE; diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c index a4d1fa4e18..7bdce3bc2e 100644 --- a/src/bin/pg_dump/dumputils.c +++ b/src/bin/pg_dump/dumputils.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.24 2006/01/11 21:24:30 momjian Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/dumputils.c,v 1.25 2006/01/21 02:16:20 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -22,8 +22,7 @@ #define supports_grant_options(version) ((version) >= 70400) static bool parseAclItem(const char *item, const char *type, const char *name, - int remoteVersion, - PQExpBuffer grantee, PQExpBuffer grantor, + int remoteVersion, PQExpBuffer grantee, PQExpBuffer grantor, PQExpBuffer privs, PQExpBuffer privswgo); static char *copyAclUserName(PQExpBuffer output, char *input); static void AddAcl(PQExpBuffer aclbuf, const char *keyword); @@ -326,7 +325,7 @@ parsePGArray(const char *atext, char ***itemarray, int *nitems) * * name: the object name, in the form to use in the commands (already quoted) * type: the object type (as seen in GRANT command: must be one of - * TABLE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, or TABLESPACE) + * TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, or TABLESPACE) * acls: the ACL string fetched from the database * owner: username of object owner (will be passed through fmtId); can be * NULL or empty string to indicate "no owner known" @@ -515,8 +514,7 @@ buildACLCommands(const char *name, const char *type, */ static bool parseAclItem(const char *item, const char *type, const char *name, - int remoteVersion, - PQExpBuffer grantee, PQExpBuffer grantor, + int remoteVersion, PQExpBuffer grantee, PQExpBuffer grantor, PQExpBuffer privs, PQExpBuffer privswgo) { char *buf; @@ -547,6 +545,7 @@ parseAclItem(const char *item, const char *type, const char *name, /* privilege codes */ #define CONVERT_PRIV(code, keywd) \ +do { \ if ((pos = strchr(eqpos + 1, code))) \ { \ if (*(pos + 1) == '*') \ @@ -561,29 +560,38 @@ parseAclItem(const char *item, const char *type, const char *name, } \ } \ else \ - all_with_go = all_without_go = false + all_with_go = all_without_go = false; \ +} while (0) resetPQExpBuffer(privs); resetPQExpBuffer(privswgo); - if (strcmp(type, "TABLE") == 0) + if (strcmp(type, "TABLE") == 0 || strcmp(type, "SEQUENCE") == 0) { - CONVERT_PRIV('a', "INSERT"); CONVERT_PRIV('r', "SELECT"); - CONVERT_PRIV('R', "RULE"); - - if (remoteVersion >= 70200) + + if (strcmp(type, "SEQUENCE") == 0) + /* sequence only */ + CONVERT_PRIV('U', "USAGE"); + else { - CONVERT_PRIV('w', "UPDATE"); - CONVERT_PRIV('d', "DELETE"); - CONVERT_PRIV('x', "REFERENCES"); - CONVERT_PRIV('t', "TRIGGER"); + /* table only */ + CONVERT_PRIV('a', "INSERT"); + CONVERT_PRIV('R', "RULE"); + if (remoteVersion >= 70200) + { + CONVERT_PRIV('d', "DELETE"); + CONVERT_PRIV('x', "REFERENCES"); + CONVERT_PRIV('t', "TRIGGER"); + } } + + /* UPDATE */ + if (remoteVersion >= 70200 || strcmp(type, "SEQUENCE") == 0) + CONVERT_PRIV('w', "UPDATE"); else - { /* 7.0 and 7.1 have a simpler worldview */ CONVERT_PRIV('w', "UPDATE,DELETE"); - } } else if (strcmp(type, "FUNCTION") == 0) CONVERT_PRIV('X', "EXECUTE"); diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index a45018533e..4a3116245e 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -15,7 +15,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.118 2005/11/22 18:17:28 momjian Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_backup_archiver.c,v 1.119 2006/01/21 02:16:20 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -1889,7 +1889,8 @@ _tocEntryRequired(TocEntry *te, RestoreOptions *ropt, bool include_acls) if (strcmp(ropt->schemaNames, te->namespace) != 0) return 0; } - if ((strcmp(te->desc, "TABLE") == 0) || (strcmp(te->desc, "TABLE DATA") == 0)) + if (strcmp(te->desc, "TABLE") == 0 || + strcmp(te->desc, "TABLE DATA") == 0) { if (!ropt->selTable) return 0; @@ -2276,8 +2277,7 @@ _getObjectDescription(PQExpBuffer buf, TocEntry *te, ArchiveHandle *AH) const char *type = te->desc; /* Use ALTER TABLE for views and sequences */ - if (strcmp(type, "VIEW") == 0 || - strcmp(type, "SEQUENCE") == 0) + if (strcmp(type, "VIEW") == 0 || strcmp(type, "SEQUENCE") == 0) type = "TABLE"; /* objects named by a schema and name */ diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 1ae6730ad0..3dffc9b3f4 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -12,7 +12,7 @@ * by PostgreSQL * * IDENTIFICATION - * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.426 2006/01/09 21:16:17 tgl Exp $ + * $PostgreSQL: pgsql/src/bin/pg_dump/pg_dump.c,v 1.427 2006/01/21 02:16:20 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -6788,7 +6788,8 @@ dumpTable(Archive *fout, TableInfo *tbinfo) /* Handle the ACL here */ namecopy = strdup(fmtId(tbinfo->dobj.name)); - dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, "TABLE", + dumpACL(fout, tbinfo->dobj.catId, tbinfo->dobj.dumpId, + (tbinfo->relkind == RELKIND_SEQUENCE) ? "SEQUENCE" : "TABLE", namecopy, tbinfo->dobj.name, tbinfo->dobj.namespace->dobj.name, tbinfo->rolname, tbinfo->relacl); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index ba39652795..e738ec2b03 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.298 2005/12/07 15:20:55 tgl Exp $ + * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.299 2006/01/21 02:16:20 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -884,7 +884,8 @@ typedef struct AlterDomainStmt */ typedef enum GrantObjectType { - ACL_OBJECT_RELATION, /* table, view, sequence */ + ACL_OBJECT_RELATION, /* table, view */ + ACL_OBJECT_SEQUENCE, /* sequence */ ACL_OBJECT_DATABASE, /* database */ ACL_OBJECT_FUNCTION, /* function */ ACL_OBJECT_LANGUAGE, /* procedural language */ diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h index 8e6cb95d25..4967970b04 100644 --- a/src/include/utils/acl.h +++ b/src/include/utils/acl.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.91 2005/12/01 02:03:01 alvherre Exp $ + * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.92 2006/01/21 02:16:21 momjian Exp $ * * NOTES * An ACL array is simply an array of AclItems, representing the union @@ -143,6 +143,7 @@ typedef ArrayType Acl; * Bitmasks defining "all rights" for each supported object type */ #define ACL_ALL_RIGHTS_RELATION (ACL_INSERT|ACL_SELECT|ACL_UPDATE|ACL_DELETE|ACL_RULE|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) #define ACL_ALL_RIGHTS_FUNCTION (ACL_EXECUTE) #define ACL_ALL_RIGHTS_LANGUAGE (ACL_USAGE) @@ -169,6 +170,7 @@ typedef enum typedef enum AclObjectKind { ACL_KIND_CLASS, /* pg_class */ + ACL_KIND_SEQUENCE, /* pg_sequence */ ACL_KIND_DATABASE, /* pg_database */ ACL_KIND_PROC, /* pg_proc */ ACL_KIND_OPER, /* pg_operator */ diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out index 354f5b2984..a18116a289 100644 --- a/src/test/regress/expected/privileges.out +++ b/src/test/regress/expected/privileges.out @@ -90,7 +90,7 @@ ERROR: permission denied for relation atest2 COPY atest2 FROM stdin; -- fail ERROR: permission denied for relation atest2 GRANT ALL ON atest1 TO PUBLIC; -- fail -WARNING: no privileges were granted +WARNING: no privileges were granted for "atest1" -- checks in subquery, both ok SELECT * FROM atest1 WHERE ( b IN ( SELECT col1 FROM atest2 ) ); a | b @@ -227,7 +227,7 @@ ERROR: language "c" is not trusted HINT: Only superusers may use untrusted languages. SET SESSION AUTHORIZATION regressuser1; GRANT USAGE ON LANGUAGE sql TO regressuser2; -- fail -WARNING: no privileges were granted +WARNING: no privileges were granted for "sql" CREATE FUNCTION testfunc1(int) RETURNS int AS 'select 2 * $1;' LANGUAGE sql; CREATE FUNCTION testfunc2(int) RETURNS int AS 'select 3 * $1;' LANGUAGE sql; REVOKE ALL ON FUNCTION testfunc1(int), testfunc2(int) FROM PUBLIC; @@ -551,7 +551,7 @@ GRANT SELECT ON atest4 TO GROUP regressgroup1 WITH GRANT OPTION; SET SESSION AUTHORIZATION regressuser2; GRANT SELECT ON atest4 TO regressuser3; GRANT UPDATE ON atest4 TO regressuser3; -- fail -WARNING: no privileges were granted +WARNING: no privileges were granted for "atest4" SET SESSION AUTHORIZATION regressuser1; REVOKE SELECT ON atest4 FROM regressuser3; -- does nothing SELECT has_table_privilege('regressuser3', 'atest4', 'SELECT'); -- true -- 2.11.0