diff --git a/doc/src/sgml/ref/grant.sgml b/doc/src/sgml/ref/grant.sgml
index 1399d049d7..98f221cf19 100644
--- a/doc/src/sgml/ref/grant.sgml
+++ b/doc/src/sgml/ref/grant.sgml
@@ -1,5 +1,5 @@
@@ -18,7 +18,7 @@ Postgres documentation
GRANT { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] }
ON [ TABLE ] objectname [, ...]
- TO { username | GROUP groupname | PUBLIC }
+ TO { username | GROUP groupname | PUBLIC } [, ...]
diff --git a/doc/src/sgml/ref/revoke.sgml b/doc/src/sgml/ref/revoke.sgml
index a9988fbc1e..f77ed62ea6 100644
--- a/doc/src/sgml/ref/revoke.sgml
+++ b/doc/src/sgml/ref/revoke.sgml
@@ -1,5 +1,5 @@
@@ -18,7 +18,7 @@ Postgres documentation
REVOKE { { SELECT | INSERT | UPDATE | DELETE | RULE | REFERENCES | TRIGGER } [,...] | ALL [ PRIVILEGES ] }
ON [ TABLE ] object [, ...]
- FROM { username | GROUP groupname | PUBLIC }
+ FROM { username | GROUP groupname | PUBLIC } [, ...]
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index f772ea3a53..2747953384 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.49 2001/06/05 19:34:56 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/aclchk.c,v 1.50 2001/06/09 23:21:54 petere Exp $
*
* NOTES
* See acl.h.
@@ -63,95 +63,132 @@ dumpacl(Acl *acl)
#endif /* ACLDEBUG */
+
/*
- * ChangeAcl
+ * Called to execute the utility commands GRANT and REVOKE
*/
void
-ChangeAcl(char *relname,
- AclItem *mod_aip,
- unsigned modechg)
+ExecuteGrantStmt(GrantStmt *stmt)
{
- unsigned i;
- Acl *old_acl,
- *new_acl;
- Relation relation;
- HeapTuple tuple;
- HeapTuple newtuple;
- Datum aclDatum;
- Datum values[Natts_pg_class];
- char nulls[Natts_pg_class];
- char replaces[Natts_pg_class];
- Relation idescs[Num_pg_class_indices];
- bool isNull;
+ List *i;
+ List *j;
- /*
- * Find the pg_class tuple matching 'relname' and extract the ACL. If
- * there's no ACL, create a default using the pg_class.relowner field.
- */
- relation = heap_openr(RelationRelationName, RowExclusiveLock);
- tuple = SearchSysCache(RELNAME,
- PointerGetDatum(relname),
- 0, 0, 0);
- if (!HeapTupleIsValid(tuple))
+ /* see comment in pg_type.h */
+ Assert(ACLITEMSIZE == sizeof(AclItem));
+
+ foreach(i, stmt->relnames)
{
+ char *relname = strVal(lfirst(i));
+ Relation relation;
+ HeapTuple tuple;
+ Form_pg_class pg_class_tuple;
+ Datum aclDatum;
+ bool isNull;
+ Acl *old_acl;
+ Acl *new_acl;
+ unsigned i;
+ HeapTuple newtuple;
+ Datum values[Natts_pg_class];
+ char nulls[Natts_pg_class];
+ char replaces[Natts_pg_class];
+
+
+ if (!pg_ownercheck(GetUserId(), relname, RELNAME))
+ elog(ERROR, "permission denied");
+
+ /* open pg_class */
+ relation = heap_openr(RelationRelationName, RowExclusiveLock);
+ tuple = SearchSysCache(RELNAME,
+ PointerGetDatum(relname),
+ 0, 0, 0);
+ if (!HeapTupleIsValid(tuple))
+ {
+ heap_close(relation, RowExclusiveLock);
+ elog(ERROR, "relation \"%s\" not found",
+ relname);
+ }
+ pg_class_tuple = (Form_pg_class) GETSTRUCT(tuple);
+
+ if (pg_class_tuple->relkind == RELKIND_INDEX)
+ elog(ERROR, "\"%s\" is an index",
+ relname);
+
+ /*
+ * If there's no ACL, create a default using the
+ * pg_class.relowner field.
+ */
+ aclDatum = SysCacheGetAttr(RELNAME, tuple, Anum_pg_class_relacl,
+ &isNull);
+ if (isNull)
+ old_acl = acldefault(relname, pg_class_tuple->relowner);
+ else
+ /* get a detoasted copy of the rel's ACL */
+ old_acl = DatumGetAclPCopy(aclDatum);
+
+#ifdef ACLDEBUG
+ dumpacl(old_acl);
+#endif
+ new_acl = old_acl;
+
+ foreach(j, stmt->grantees)
+ {
+ PrivGrantee *grantee = (PrivGrantee *)lfirst(j);
+ char *granteeString;
+ char *aclString;
+ AclItem aclitem;
+ unsigned modechg;
+
+ if (grantee->username)
+ granteeString = aclmakeuser("U", grantee->username);
+ else if (grantee->groupname)
+ granteeString = aclmakeuser("G", grantee->groupname);
+ else
+ granteeString = aclmakeuser("A", "");
+
+ aclString = makeAclString(stmt->privileges, granteeString,
+ stmt->is_grant ? '+' : '-');
+
+ /* Convert string ACL spec into internal form */
+ aclparse(aclString, &aclitem, &modechg);
+ new_acl = aclinsert3(new_acl, &aclitem, modechg);
+#ifdef ACLDEBUG
+ dumpacl(new_acl);
+#endif
+ }
+
+ /* finished building new ACL value, now insert it */
+ for (i = 0; i < Natts_pg_class; ++i)
+ {
+ replaces[i] = ' ';
+ nulls[i] = ' '; /* ignored if replaces[i]==' ' anyway */
+ values[i] = (Datum) NULL; /* ignored if replaces[i]==' ' anyway */
+ }
+ replaces[Anum_pg_class_relacl - 1] = 'r';
+ values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
+ newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
+
+ ReleaseSysCache(tuple);
+
+ simple_heap_update(relation, &newtuple->t_self, newtuple);
+
+ {
+ /* keep the catalog indexes up to date */
+ Relation idescs[Num_pg_class_indices];
+ CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
+ idescs);
+ CatalogIndexInsert(idescs, Num_pg_class_indices, relation, newtuple);
+ CatalogCloseIndices(Num_pg_class_indices, idescs);
+ }
+
+ pfree(old_acl);
+ pfree(new_acl);
+
heap_close(relation, RowExclusiveLock);
- elog(ERROR, "ChangeAcl: class \"%s\" not found",
- relname);
}
-
- aclDatum = SysCacheGetAttr(RELNAME, tuple, Anum_pg_class_relacl,
- &isNull);
- if (isNull)
- {
- /* No ACL, so build default ACL for rel */
- AclId ownerId;
-
- ownerId = ((Form_pg_class) GETSTRUCT(tuple))->relowner;
- old_acl = acldefault(relname, ownerId);
- }
- else
- {
- /* get a detoasted copy of the rel's ACL */
- old_acl = DatumGetAclPCopy(aclDatum);
- }
-
-#ifdef ACLDEBUG
- dumpacl(old_acl);
-#endif
-
- new_acl = aclinsert3(old_acl, mod_aip, modechg);
-
-#ifdef ACLDEBUG
- dumpacl(new_acl);
-#endif
-
- for (i = 0; i < Natts_pg_class; ++i)
- {
- replaces[i] = ' ';
- nulls[i] = ' '; /* ignored if replaces[i] == ' ' anyway */
- values[i] = (Datum) NULL; /* ignored if replaces[i] == ' '
- * anyway */
- }
- replaces[Anum_pg_class_relacl - 1] = 'r';
- values[Anum_pg_class_relacl - 1] = PointerGetDatum(new_acl);
- newtuple = heap_modifytuple(tuple, relation, values, nulls, replaces);
-
- ReleaseSysCache(tuple);
-
- simple_heap_update(relation, &newtuple->t_self, newtuple);
-
- /* keep the catalog indices up to date */
- CatalogOpenIndices(Num_pg_class_indices, Name_pg_class_indices,
- idescs);
- CatalogIndexInsert(idescs, Num_pg_class_indices, relation, newtuple);
- CatalogCloseIndices(Num_pg_class_indices, idescs);
-
- heap_close(relation, RowExclusiveLock);
-
- pfree(old_acl);
- pfree(new_acl);
}
+
+
AclId
get_grosysid(char *groname)
{
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 07907b6368..77ae4fb781 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -15,7 +15,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.143 2001/06/05 05:26:03 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.144 2001/06/09 23:21:54 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -24,7 +24,6 @@
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
-#include "utils/acl.h"
/*
@@ -1856,14 +1855,29 @@ _copyAlterTableStmt(AlterTableStmt *from)
return newnode;
}
-static ChangeACLStmt *
-_copyChangeACLStmt(ChangeACLStmt *from)
+static GrantStmt *
+_copyGrantStmt(GrantStmt *from)
{
- ChangeACLStmt *newnode = makeNode(ChangeACLStmt);
+ GrantStmt *newnode = makeNode(GrantStmt);
- Node_Copy(from, newnode, relNames);
- if (from->aclString)
- newnode->aclString = pstrdup(from->aclString);
+ newnode->is_grant = from->is_grant;
+ Node_Copy(from, newnode, relnames);
+ if (from->privileges)
+ newnode->privileges = pstrdup(from->privileges);
+ Node_Copy(from, newnode, grantees);
+
+ return newnode;
+}
+
+static PrivGrantee *
+_copyPrivGrantee(PrivGrantee *from)
+{
+ PrivGrantee *newnode = makeNode(PrivGrantee);
+
+ if (from->username)
+ newnode->username = pstrdup(from->username);
+ if (from->groupname)
+ newnode->groupname = pstrdup(from->groupname);
return newnode;
}
@@ -2729,8 +2743,8 @@ copyObject(void *from)
case T_AlterTableStmt:
retval = _copyAlterTableStmt(from);
break;
- case T_ChangeACLStmt:
- retval = _copyChangeACLStmt(from);
+ case T_GrantStmt:
+ retval = _copyGrantStmt(from);
break;
case T_ClosePortalStmt:
retval = _copyClosePortalStmt(from);
@@ -2943,6 +2957,9 @@ copyObject(void *from)
case T_FkConstraint:
retval = _copyFkConstraint(from);
break;
+ case T_PrivGrantee:
+ retval = _copyPrivGrantee(from);
+ break;
default:
elog(ERROR, "copyObject: don't know how to copy node type %d",
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index 656c1e9ea6..f7bfcc1977 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -20,7 +20,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.91 2001/06/05 05:26:03 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.92 2001/06/09 23:21:54 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -29,7 +29,6 @@
#include "nodes/plannodes.h"
#include "nodes/relation.h"
-#include "utils/acl.h"
#include "utils/datum.h"
@@ -755,16 +754,27 @@ _equalAlterTableStmt(AlterTableStmt *a, AlterTableStmt *b)
}
static bool
-_equalChangeACLStmt(ChangeACLStmt *a, ChangeACLStmt *b)
+_equalGrantStmt(GrantStmt *a, GrantStmt *b)
{
- if (!equal(a->relNames, b->relNames))
+ if (a->is_grant != b->is_grant)
return false;
- if (!equalstr(a->aclString, b->aclString))
+ if (!equal(a->relnames, b->relnames))
+ return false;
+ if (!equalstr(a->privileges, b->privileges))
+ return false;
+ if (!equal(a->grantees, b->grantees))
return false;
return true;
}
+static bool
+_equalPrivGrantee(PrivGrantee *a, PrivGrantee *b)
+{
+ return equalstr(a->username, b->username)
+ && equalstr(a->groupname, b->groupname);
+}
+
static bool
_equalClosePortalStmt(ClosePortalStmt *a, ClosePortalStmt *b)
{
@@ -1898,8 +1908,8 @@ equal(void *a, void *b)
case T_AlterTableStmt:
retval = _equalAlterTableStmt(a, b);
break;
- case T_ChangeACLStmt:
- retval = _equalChangeACLStmt(a, b);
+ case T_GrantStmt:
+ retval = _equalGrantStmt(a, b);
break;
case T_ClosePortalStmt:
retval = _equalClosePortalStmt(a, b);
@@ -2113,6 +2123,9 @@ equal(void *a, void *b)
case T_FkConstraint:
retval = _equalFkConstraint(a, b);
break;
+ case T_PrivGrantee:
+ retval = _equalPrivGrantee(a, b);
+ break;
default:
elog(NOTICE, "equal: don't know whether nodes of type %d are equal",
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 308b49fd72..263830244d 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11,7 +11,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.229 2001/06/07 04:50:56 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/gram.y,v 2.230 2001/06/09 23:21:54 petere Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -177,7 +177,9 @@ static void doNegateFloat(Value *v);
OptUseOp, opt_class, SpecialRuleRelation
%type opt_level, opt_encoding
-%type privileges, operation_commalist, grantee
+%type privileges, operation_commalist
+%type grantee
+%type grantee_list
%type operation, TriggerOneEvent
%type stmtblock, stmtmulti,
@@ -2241,14 +2243,18 @@ from_in: IN
/*****************************************************************************
*
- * QUERY:
- * GRANT [privileges] ON [relation_name_list] TO [GROUP] grantee
+ * GRANT privileges ON [TABLE] relation_name_list TO [GROUP] grantee, ...
*
*****************************************************************************/
-GrantStmt: GRANT privileges ON opt_table relation_name_list TO grantee opt_with_grant
+GrantStmt: GRANT privileges ON opt_table relation_name_list TO grantee_list opt_with_grant
{
- $$ = (Node*)makeAclStmt($2,$5,$7,'+');
+ GrantStmt *n = makeNode(GrantStmt);
+ n->is_grant = true;
+ n->relnames = $5;
+ n->privileges = $2;
+ n->grantees = $7;
+ $$ = (Node*)n;
}
;
@@ -2308,18 +2314,31 @@ operation: SELECT
grantee: PUBLIC
{
- $$ = aclmakeuser("A","");
+ PrivGrantee *n = makeNode(PrivGrantee);
+ n->username = NULL;
+ n->groupname = NULL;
+ $$ = (Node *)n;
}
| GROUP ColId
{
- $$ = aclmakeuser("G",$2);
+ PrivGrantee *n = makeNode(PrivGrantee);
+ n->username = NULL;
+ n->groupname = $2;
+ $$ = (Node *)n;
}
| ColId
{
- $$ = aclmakeuser("U",$1);
+ PrivGrantee *n = makeNode(PrivGrantee);
+ n->username = $1;
+ n->groupname = NULL;
+ $$ = (Node *)n;
}
;
+grantee_list: grantee { $$ = makeList1($1); }
+ | grantee_list ',' grantee { $$ = lappend($1, $3); }
+
+
opt_with_grant: WITH GRANT OPTION
{
elog(ERROR,"WITH GRANT OPTION is not supported. Only relation owners can set privileges");
@@ -2330,14 +2349,18 @@ opt_with_grant: WITH GRANT OPTION
/*****************************************************************************
*
- * QUERY:
- * REVOKE [privileges] ON [relation_name] FROM [user]
+ * REVOKE privileges ON [TABLE] relation_name_list FROM user, ...
*
*****************************************************************************/
-RevokeStmt: REVOKE privileges ON opt_table relation_name_list FROM grantee
+RevokeStmt: REVOKE privileges ON opt_table relation_name_list FROM grantee_list
{
- $$ = (Node*)makeAclStmt($2,$5,$7,'-');
+ GrantStmt *n = makeNode(GrantStmt);
+ n->is_grant = false;
+ n->relnames = $5;
+ n->privileges = $2;
+ n->grantees = $7;
+ $$ = (Node *)n;
}
;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 5e6a044b92..bef1d6844a 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.112 2001/05/30 20:52:32 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.113 2001/06/09 23:21:54 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -472,13 +472,13 @@ ProcessUtility(Node *parsetree,
break;
- case T_ChangeACLStmt:
+ case T_GrantStmt:
{
- ChangeACLStmt *stmt = (ChangeACLStmt *) parsetree;
+ GrantStmt *stmt = (GrantStmt *) parsetree;
+ commandTag = stmt->is_grant ? "GRANT" : "REVOKE";
+ set_ps_display(commandTag);
- set_ps_display(commandTag = "CHANGE");
-
- ExecuteChangeACLStmt(stmt);
+ ExecuteGrantStmt(stmt);
}
break;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 1da525bd03..eeb9543027 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.60 2001/06/05 19:34:56 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/acl.c,v 1.61 2001/06/09 23:21:55 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -27,15 +27,13 @@
#include "utils/memutils.h"
#include "utils/syscache.h"
-static char *getid(char *s, char *n);
-static bool aclitemeq(AclItem *a1, AclItem *a2);
-static bool aclitemgt(AclItem *a1, AclItem *a2);
-static char *aclparse(char *s, AclItem *aip, unsigned *modechg);
+static const char *getid(const char *s, char *n);
+static bool aclitemeq(const AclItem *a1, const AclItem *a2);
+static bool aclitemgt(const AclItem *a1, const AclItem *a2);
#define ACL_IDTYPE_GID_KEYWORD "group"
#define ACL_IDTYPE_UID_KEYWORD "user"
-
/*
* getid
* Consumes the first alphanumeric string (identifier) found in string
@@ -48,11 +46,11 @@ static char *aclparse(char *s, AclItem *aip, unsigned *modechg);
* - loads the identifier into 'name'. (If no identifier is found, 'name'
* contains an empty string.) name must be NAMEDATALEN bytes.
*/
-static char *
-getid(char *s, char *n)
+static const char *
+getid(const char *s, char *n)
{
unsigned len;
- char *id;
+ const char *id;
int in_quotes = 0;
Assert(s && n);
@@ -105,8 +103,8 @@ getid(char *s, char *n)
* UID/GID, id type identifier and mode type values.
* - loads 'modechg' with the mode change flag.
*/
-static char *
-aclparse(char *s, AclItem *aip, unsigned *modechg)
+const char *
+aclparse(const char *s, AclItem *aip, unsigned *modechg)
{
HeapTuple htup;
char name[NAMEDATALEN];
@@ -245,7 +243,7 @@ makeacl(int n)
Datum
aclitemin(PG_FUNCTION_ARGS)
{
- char *s = PG_GETARG_CSTRING(0);
+ const char *s = PG_GETARG_CSTRING(0);
AclItem *aip;
unsigned modechg;
@@ -351,13 +349,13 @@ aclitemout(PG_FUNCTION_ARGS)
* a boolean value indicating = or >
*/
static bool
-aclitemeq(AclItem *a1, AclItem *a2)
+aclitemeq(const AclItem *a1, const AclItem *a2)
{
return a1->ai_idtype == a2->ai_idtype && a1->ai_id == a2->ai_id;
}
static bool
-aclitemgt(AclItem *a1, AclItem *a2)
+aclitemgt(const AclItem *a1, const AclItem *a2)
{
return ((a1->ai_idtype > a2->ai_idtype) ||
(a1->ai_idtype == a2->ai_idtype && a1->ai_id > a2->ai_id));
@@ -371,7 +369,7 @@ aclitemgt(AclItem *a1, AclItem *a2)
* newly-created tables (or any table with a NULL acl entry in pg_class)
*/
Acl *
-acldefault(char *relname, AclId ownerid)
+acldefault(const char *relname, AclId ownerid)
{
Acl *acl;
AclItem *aip;
@@ -398,7 +396,7 @@ acldefault(char *relname, AclId ownerid)
* NB: caller is responsible for having detoasted the input ACL, if needed.
*/
Acl *
-aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg)
+aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg)
{
Acl *new_acl;
AclItem *old_aip,
@@ -595,41 +593,6 @@ aclcontains(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(false);
}
-/*
- * ExecuteChangeACLStmt
- * Called to execute the utility command type ChangeACLStmt
- */
-void
-ExecuteChangeACLStmt(ChangeACLStmt *stmt)
-{
- AclItem aclitem;
- unsigned modechg;
- List *i;
-
- /* see comment in pg_type.h */
- Assert(ACLITEMSIZE == sizeof(AclItem));
-
- /* Convert string ACL spec into internal form */
- aclparse(stmt->aclString, &aclitem, &modechg);
-
- foreach(i, stmt->relNames)
- {
- char *relname = strVal(lfirst(i));
- Relation rel;
-
- rel = heap_openr(relname, AccessExclusiveLock);
- if (rel && rel->rd_rel->relkind == RELKIND_INDEX)
- elog(ERROR, "\"%s\" is an index relation",
- relname);
- if (!pg_ownercheck(GetUserId(), relname, RELNAME))
- elog(ERROR, "you do not own class \"%s\"",
- relname);
- ChangeAcl(relname, &aclitem, modechg);
- /* close rel, but keep lock until end of xact */
- heap_close(rel, NoLock);
- }
-}
-
/*
* Parser support routines for ACL-related statements.
@@ -648,7 +611,7 @@ ExecuteChangeACLStmt(ChangeACLStmt *stmt)
* does not add duplicate privileges
*/
char *
-aclmakepriv(char *old_privlist, char new_priv)
+aclmakepriv(const char *old_privlist, char new_priv)
{
char *priv;
int i;
@@ -698,7 +661,7 @@ aclmakepriv(char *old_privlist, char new_priv)
* Per above comments, we can't try to resolve a user or group name here.
*/
char *
-aclmakeuser(char *user_type, char *user)
+aclmakeuser(const char *user_type, const char *user)
{
char *user_list;
@@ -707,22 +670,20 @@ aclmakeuser(char *user_type, char *user)
return user_list;
}
+
/*
- * makeAclStmt:
- * create a ChangeACLStmt at parse time.
- * we take in the privileges, relation_name_list, and grantee
- * as well as a single character '+' or '-' to indicate grant or revoke
+ * makeAclString: We take in the privileges and grantee as well as a
+ * single character '+' or '-' to indicate grant or revoke.
*
* We convert the information to the same external form recognized by
- * aclitemin (see aclparse), and save that string in the ChangeACLStmt.
- * Conversion to internal form happens when the statement is executed.
+ * aclitemin (see aclparse) and return that string. Conversion to
+ * internal form happens when the statement is executed.
*/
-ChangeACLStmt *
-makeAclStmt(char *privileges, List *rel_list, char *grantee,
- char grant_or_revoke)
+char *
+makeAclString(const char *privileges, const char *grantee, char grant_or_revoke)
{
- ChangeACLStmt *n = makeNode(ChangeACLStmt);
StringInfoData str;
+ char *ret;
initStringInfo(&str);
@@ -745,9 +706,7 @@ makeAclStmt(char *privileges, List *rel_list, char *grantee,
appendStringInfo(&str, "%c%s",
grant_or_revoke, privileges);
}
- n->relNames = rel_list;
- n->aclString = pstrdup(str.data);
-
+ ret = pstrdup(str.data);
pfree(str.data);
- return n;
+ return ret;
}
diff --git a/src/backend/utils/adt/varchar.c b/src/backend/utils/adt/varchar.c
index cdd76afb55..d70a256dfd 100644
--- a/src/backend/utils/adt/varchar.c
+++ b/src/backend/utils/adt/varchar.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.79 2001/06/01 17:49:16 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/varchar.c,v 1.80 2001/06/09 23:21:55 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -17,7 +17,7 @@
#include "access/hash.h"
#include "catalog/pg_type.h"
#include "miscadmin.h"
-#include "utils/acl.h"
+#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index 25fe3955e1..d62583c4d2 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: nodes.h,v 1.89 2001/04/24 00:08:38 tgl Exp $
+ * $Id: nodes.h,v 1.90 2001/06/09 23:21:55 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -148,7 +148,7 @@ typedef enum NodeTag
T_SelectStmt,
T_AlterTableStmt,
T_SetOperationStmt,
- T_ChangeACLStmt,
+ T_GrantStmt,
T_ClosePortalStmt,
T_ClusterStmt,
T_CopyStmt,
@@ -224,6 +224,7 @@ typedef enum NodeTag
T_CaseWhen,
T_RowMarkXXX, /* not used anymore; tag# available */
T_FkConstraint,
+ T_PrivGrantee,
/*
* TAGS FOR FUNCTION-CALL CONTEXT AND RESULTINFO NODES (see fmgr.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 31aadb449d..fe2d1bb7ff 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parsenodes.h,v 1.130 2001/06/04 23:27:23 momjian Exp $
+ * $Id: parsenodes.h,v 1.131 2001/06/09 23:21:55 petere Exp $
*
*-------------------------------------------------------------------------
*/
@@ -137,15 +137,27 @@ typedef struct AlterTableStmt
} AlterTableStmt;
/* ----------------------
- * Change ACL Statement
+ * Grant Statement
* ----------------------
*/
-typedef struct ChangeACLStmt
+
+typedef struct GrantStmt
{
NodeTag type;
- List *relNames;
- char *aclString;
-} ChangeACLStmt;
+ bool is_grant; /* not revoke */
+ List *relnames;
+ char *privileges;
+ List *grantees;
+} GrantStmt;
+
+
+typedef struct PrivGrantee
+{
+ NodeTag type;
+ char *username; /* if both are NULL then PUBLIC */
+ char *groupname;
+} PrivGrantee;
+
/* ----------------------
* Close Portal Statement
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index 2ea98d5cb6..1cf751fad1 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: acl.h,v 1.33 2001/06/05 19:34:56 tgl Exp $
+ * $Id: acl.h,v 1.34 2001/06/09 23:21:55 petere Exp $
*
* NOTES
* For backward-compatibility purposes we have to allow there
@@ -170,17 +170,14 @@ extern char *aclcheck_error_strings[];
/*
* routines used internally
*/
-extern Acl *acldefault(char *relname, AclId ownerid);
-
-extern Acl *aclinsert3(Acl *old_acl, AclItem *mod_aip, unsigned modechg);
+extern Acl *acldefault(const char *relname, AclId ownerid);
+extern Acl *aclinsert3(const Acl *old_acl, const AclItem *mod_aip, unsigned modechg);
/*
* routines used by the parser
*/
-extern char *aclmakepriv(char *old_privlist, char new_priv);
-extern char *aclmakeuser(char *user_type, char *user);
-extern ChangeACLStmt *makeAclStmt(char *privs, List *rel_list, char *grantee,
- char grant_or_revoke);
+extern char *aclmakepriv(const char *old_privlist, char new_priv);
+extern char *aclmakeuser(const char *user_type, const char *user);
/*
* exported routines (from acl.c)
@@ -191,12 +188,13 @@ extern Datum aclitemout(PG_FUNCTION_ARGS);
extern Datum aclinsert(PG_FUNCTION_ARGS);
extern Datum aclremove(PG_FUNCTION_ARGS);
extern Datum aclcontains(PG_FUNCTION_ARGS);
-extern void ExecuteChangeACLStmt(ChangeACLStmt *stmt);
+extern const char *aclparse(const char *s, AclItem *aip, unsigned *modechg);
+extern char *makeAclString(const char *privileges, const char *grantee, char grant_or_revoke);
/*
* prototypes for functions in aclchk.c
*/
-extern void ChangeAcl(char *relname, AclItem *mod_aip, unsigned modechg);
+extern void ExecuteGrantStmt(GrantStmt *stmt);
extern AclId get_grosysid(char *groname);
extern char *get_groname(AclId grosysid);
diff --git a/src/test/regress/expected/privileges.out b/src/test/regress/expected/privileges.out
index cb376e0bbc..ea19667a16 100644
--- a/src/test/regress/expected/privileges.out
+++ b/src/test/regress/expected/privileges.out
@@ -39,7 +39,7 @@ SELECT * FROM atest1;
(0 rows)
GRANT ALL ON atest1 TO regressuser2;
-GRANT SELECT ON atest1 TO regressuser3;
+GRANT SELECT ON atest1 TO regressuser3, regressuser4;
SELECT * FROM atest1;
a | b
---+---
@@ -90,7 +90,7 @@ ERROR: LOCK TABLE: permission denied
COPY atest2 FROM stdin; -- fail
ERROR: atest2: Permission denied.
GRANT ALL ON atest1 TO PUBLIC; -- fail
-ERROR: you do not own class "atest1"
+ERROR: permission denied
-- checks in subquery, both ok
SELECT * FROM atest1 WHERE ( b IN ( SELECT col1 FROM atest2 ) );
a | b
@@ -146,6 +146,13 @@ SELECT * FROM atest2 WHERE ( col1 IN ( SELECT b FROM atest1 ) );
ERROR: atest2: Permission denied.
SET SESSION AUTHORIZATION regressuser4;
COPY atest2 FROM stdin; -- ok
+SELECT * FROM atest1; -- ok
+ a | b
+---+-----
+ 1 | two
+ 1 | two
+(2 rows)
+
-- groups
SET SESSION AUTHORIZATION regressuser3;
CREATE TABLE atest3 (one int, two int, three int);
@@ -167,8 +174,7 @@ SELECT * FROM atestv1; -- ok
1 | two
(2 rows)
-GRANT SELECT ON atestv1 TO regressuser4;
-GRANT SELECT ON atestv3 TO regressuser4;
+GRANT SELECT ON atestv1, atestv3 TO regressuser4;
SET SESSION AUTHORIZATION regressuser4;
SELECT * FROM atestv1; -- ok
a | b
diff --git a/src/test/regress/sql/privileges.sql b/src/test/regress/sql/privileges.sql
index 1558273f7b..2a09666083 100644
--- a/src/test/regress/sql/privileges.sql
+++ b/src/test/regress/sql/privileges.sql
@@ -34,7 +34,7 @@ REVOKE ALL ON atest1 FROM PUBLIC;
SELECT * FROM atest1;
GRANT ALL ON atest1 TO regressuser2;
-GRANT SELECT ON atest1 TO regressuser3;
+GRANT SELECT ON atest1 TO regressuser3, regressuser4;
SELECT * FROM atest1;
CREATE TABLE atest2 (col1 varchar(10), col2 boolean);
@@ -93,6 +93,7 @@ SET SESSION AUTHORIZATION regressuser4;
COPY atest2 FROM stdin; -- ok
bar true
\.
+SELECT * FROM atest1; -- ok
-- groups
@@ -117,8 +118,7 @@ CREATE VIEW atestv2 AS SELECT * FROM atest2;
CREATE VIEW atestv3 AS SELECT * FROM atest3; -- ok
SELECT * FROM atestv1; -- ok
-GRANT SELECT ON atestv1 TO regressuser4;
-GRANT SELECT ON atestv3 TO regressuser4;
+GRANT SELECT ON atestv1, atestv3 TO regressuser4;
SET SESSION AUTHORIZATION regressuser4;