public inbox for [email protected]  
help / color / mirror / Atom feed
From: Alvaro Herrera <[email protected]>
To: Tom Lane <[email protected]>
To: Patches <[email protected]>
Subject: aclchk.c refactor
Date: Mon, 21 Nov 2005 12:16:52 -0300
Message-ID: <[email protected]> (raw)
In-Reply-To: <[email protected]>
References: <[email protected]>
	<[email protected]>
	<[email protected]>
	<[email protected]>

I intend to apply later today the attached patch in order to reduce some
code duplication in aclchk.c and clean a bit the API I just introduced
in the previous patch.  This reduces aclchk.c from 2377 lines to 2206.

-- 
Alvaro Herrera                                http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.

Index: src/backend/catalog/aclchk.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/aclchk.c,v
retrieving revision 1.121
diff -c -r1.121 aclchk.c
*** src/backend/catalog/aclchk.c	21 Nov 2005 12:49:30 -0000	1.121
--- src/backend/catalog/aclchk.c	21 Nov 2005 15:05:19 -0000
***************
*** 42,69 ****
  #include "utils/syscache.h"
  
  
! static void ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
! 				   AclMode privileges, List *grantees, bool grant_option,
! 				   DropBehavior behavior);
! static void ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
! 				   AclMode privileges, List *grantees, bool grant_option,
! 				   DropBehavior behavior);
! static void ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
! 				   AclMode privileges, List *grantees, bool grant_option,
! 				   DropBehavior behavior);
! static void ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
! 				   AclMode privileges, List *grantees, bool grant_option,
! 				   DropBehavior behavior);
! static void ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
! 					AclMode privileges, List *grantees, bool grant_option,
! 					DropBehavior behavior);
! static void ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
! 					 AclMode privileges, List *grantees, bool grant_option,
! 					 DropBehavior behavior);
! static List *objectNamesToOids(GrantObjectType objtype, List *objnames);
  
  static AclMode string_to_privilege(const char *privname);
  static const char *privilege_to_string(AclMode privilege);
  
  
  #ifdef ACLDEBUG
--- 42,62 ----
  #include "utils/syscache.h"
  
  
! static void ExecGrant_Relation(InternalGrant *grantStmt);
! static void ExecGrant_Database(InternalGrant *grantStmt);
! static void ExecGrant_Function(InternalGrant *grantStmt);
! static void ExecGrant_Language(InternalGrant *grantStmt);
! static void ExecGrant_Namespace(InternalGrant *grantStmt);
! static void ExecGrant_Tablespace(InternalGrant *grantStmt);
  
+ static List *objectNamesToOids(GrantObjectType objtype, List *objnames);
  static AclMode string_to_privilege(const char *privname);
  static const char *privilege_to_string(AclMode privilege);
+ static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
+ 										bool all_privs, AclMode privileges,
+ 										Oid objectId, Oid grantorId,
+ 										AclMode whole_mask,
+ 										AclObjectKind objkind, char *objname);
  
  
  #ifdef ACLDEBUG
***************
*** 160,172 ****
  void
  ExecuteGrantStmt(GrantStmt *stmt)
  {
! 	List	   *objects;
! 	List	   *grantees = NIL;
! 	AclMode		privileges;
  	ListCell   *cell;
! 	bool		all_privs;
! 	AclMode all_privileges = (AclMode) 0;
! 	char	*errormsg = NULL;
  
  	/*
  	 * Convert the PrivGrantee list into an Oid list.  Note that at this point
--- 153,174 ----
  void
  ExecuteGrantStmt(GrantStmt *stmt)
  {
! 	InternalGrant istmt;
  	ListCell   *cell;
! 	char	   *errormsg;
! 	AclMode		all_privileges;
! 
! 	/*
! 	 * Turn the regular GrantStmt into the InternalGrant form.
! 	 */
! 	istmt.is_grant = stmt->is_grant;
! 	istmt.objtype = stmt->objtype;
! 	istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects);
! 	/* all_privs to be filled below */
! 	/* privileges to be filled below */
! 	/* grantees to be filled below */
! 	istmt.grant_option = stmt->grant_option;
! 	istmt.behavior = stmt->behavior;
  
  	/*
  	 * Convert the PrivGrantee list into an Oid list.  Note that at this point
***************
*** 180,194 ****
  		PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
  
  		if (grantee->rolname == NULL)
! 			grantees = lappend_oid(grantees, ACL_ID_PUBLIC);
  		else
! 			grantees = lappend_oid(grantees,
! 								   get_roleid_checked(grantee->rolname));
  	}
  
  	/*
! 	 * Convert stmt->privileges, a textual list, into an AclMode bitmask
! 	 * appropiate for the given object class.
  	 */
  	switch (stmt->objtype)
  	{
--- 182,196 ----
  		PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
  
  		if (grantee->rolname == NULL)
! 			istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC);
  		else
! 			istmt.grantees =
! 				lappend_oid(istmt.grantees,
! 							get_roleid_checked(grantee->rolname));
  	}
  
  	/*
! 	 * Convert stmt->privileges, a textual list, into an AclMode bitmask.
  	 */
  	switch (stmt->objtype)
  	{
***************
*** 217,235 ****
  			errormsg = _("invalid privilege type %s for tablespace");
  			break;
  		default:
  			elog(ERROR, "unrecognized GrantStmt.objtype: %d",
  				 (int) stmt->objtype);
  	}
  
  	if (stmt->privileges == NIL)
  	{
! 		all_privs = true;
! 		privileges = all_privileges;
  	}
  	else
  	{
! 		all_privs = false;
! 		privileges = ACL_NO_RIGHTS;
  		foreach(cell, stmt->privileges)
  		{
  			char	   *privname = strVal(lfirst(cell));
--- 219,244 ----
  			errormsg = _("invalid privilege type %s for tablespace");
  			break;
  		default:
+ 			/* keep compiler quiet */
+ 			all_privileges = ACL_NO_RIGHTS;
+ 			errormsg = NULL;
  			elog(ERROR, "unrecognized GrantStmt.objtype: %d",
  				 (int) stmt->objtype);
  	}
  
  	if (stmt->privileges == NIL)
  	{
! 		istmt.all_privs = true;
! 		/*
! 		 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
! 		 * depending on the object type
! 		 */
! 		istmt.privileges = ACL_NO_RIGHTS;
  	}
  	else
  	{
! 		istmt.all_privs = false;
! 		istmt.privileges = ACL_NO_RIGHTS;
  		foreach(cell, stmt->privileges)
  		{
  			char	   *privname = strVal(lfirst(cell));
***************
*** 241,301 ****
  						 errmsg(errormsg,
  								privilege_to_string(priv))));
  
! 			privileges |= priv;
  		}
  	}
  
! 	/* Turn the list of object names into an Oid list */
! 	objects = objectNamesToOids(stmt->objtype, stmt->objects);
! 
! 	ExecGrantStmt_oids(stmt->is_grant, stmt->objtype, objects, all_privs,
! 					   privileges, grantees, stmt->grant_option,
! 					   stmt->behavior);
  }
  
  /*
   * ExecGrantStmt_oids
   *
!  * "Internal" entrypoint for granting and revoking privileges.  The arguments
!  * it receives are lists of Oids or have been otherwise converted from text
!  * format to internal format.
   */
  void
! ExecGrantStmt_oids(bool is_grant, GrantObjectType objtype, List *objects,
! 				   bool all_privs, AclMode privileges, List *grantees,
! 				   bool grant_option, DropBehavior behavior)
  {
! 	switch (objtype)
  	{
  		case ACL_OBJECT_RELATION:
! 			ExecGrant_Relation(is_grant, objects, all_privs, privileges,
! 							   grantees, grant_option, behavior);
  			break;
  		case ACL_OBJECT_DATABASE:
! 			ExecGrant_Database(is_grant, objects, all_privs, privileges,
! 							   grantees, grant_option, behavior);
  			break;
  		case ACL_OBJECT_FUNCTION:
! 			ExecGrant_Function(is_grant, objects, all_privs, privileges,
! 							   grantees, grant_option, behavior);
  			break;
  		case ACL_OBJECT_LANGUAGE:
! 			ExecGrant_Language(is_grant, objects, all_privs, privileges,
! 							   grantees, grant_option, behavior);
  			break;
  		case ACL_OBJECT_NAMESPACE:
! 			ExecGrant_Namespace(is_grant, objects, all_privs,
! 								privileges, grantees, grant_option,
! 								behavior);
  			break;
  		case ACL_OBJECT_TABLESPACE:
! 			ExecGrant_Tablespace(is_grant, objects, all_privs,
! 								 privileges, grantees, grant_option,
! 								 behavior);
  			break;
  		default:
  			elog(ERROR, "unrecognized GrantStmt.objtype: %d",
! 				 (int) objtype);
  	}
  }
  
--- 250,293 ----
  						 errmsg(errormsg,
  								privilege_to_string(priv))));
  
! 			istmt.privileges |= priv;
  		}
  	}
  
! 	ExecGrantStmt_oids(&istmt);
  }
  
  /*
   * ExecGrantStmt_oids
   *
!  * "Internal" entrypoint for granting and revoking privileges.
   */
  void
! ExecGrantStmt_oids(InternalGrant *istmt)
  {
! 	switch (istmt->objtype)
  	{
  		case ACL_OBJECT_RELATION:
! 			ExecGrant_Relation(istmt);
  			break;
  		case ACL_OBJECT_DATABASE:
! 			ExecGrant_Database(istmt);
  			break;
  		case ACL_OBJECT_FUNCTION:
! 			ExecGrant_Function(istmt);
  			break;
  		case ACL_OBJECT_LANGUAGE:
! 			ExecGrant_Language(istmt);
  			break;
  		case ACL_OBJECT_NAMESPACE:
! 			ExecGrant_Namespace(istmt);
  			break;
  		case ACL_OBJECT_TABLESPACE:
! 			ExecGrant_Tablespace(istmt);
  			break;
  		default:
  			elog(ERROR, "unrecognized GrantStmt.objtype: %d",
! 				 (int) istmt->objtype);
  	}
  }
  
***************
*** 443,462 ****
  	return objects;
  }
  
  static void
! ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
! 				   AclMode privileges, List *grantees, bool grant_option,
! 				   DropBehavior behavior)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (all_privs && privileges == ACL_NO_RIGHTS)
! 		privileges = ACL_ALL_RIGHTS_RELATION;
  
  	relation = heap_open(RelationRelationId, RowExclusiveLock);
  
! 	foreach (cell, objects)
  	{
  		Oid			relOid = lfirst_oid(cell);
  		Datum		aclDatum;
--- 435,513 ----
  	return objects;
  }
  
+ /*
+  * Restrict the privileges to what we can actually grant, and emit
+  * the standards-mandated warning and error messages.
+  */
+ static AclMode
+ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
+ 						 AclMode privileges, Oid objectId, Oid grantorId,
+ 						 AclMode whole_mask, AclObjectKind objkind,
+ 						 char *objname)
+ {
+ 	AclMode	this_privileges;
+ 
+ 	/*
+ 	 * If we found no grant options, consider whether to issue a hard
+ 	 * error.  Per spec, having any privilege at all on the object will
+ 	 * get you by here.
+ 	 */
+ 	if (avail_goptions == ACL_NO_RIGHTS)
+ 	{
+ 		if (pg_class_aclmask(objectId,
+ 							 grantorId,
+ 							 whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
+ 							 ACLMASK_ANY) == ACL_NO_RIGHTS)
+ 			aclcheck_error(ACLCHECK_NO_PRIV, objkind, objname);
+ 	}
+ 
+ 	/*
+ 	 * Restrict the operation to what we can actually grant or revoke, and
+ 	 * issue a warning if appropriate.	(For REVOKE this isn't quite what
+ 	 * the spec says to do: the spec seems to want a warning only if no
+ 	 * privilege bits actually change in the ACL. In practice that
+ 	 * behavior seems much too noisy, as well as inconsistent with the
+ 	 * GRANT case.)
+ 	 */
+ 	this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
+ 	if (is_grant)
+ 	{
+ 		if (this_privileges == 0)
+ 			ereport(WARNING,
+ 					(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
+ 					 errmsg("no privileges were granted")));
+ 		else if (!all_privs && this_privileges != privileges)
+ 			ereport(WARNING,
+ 					(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
+ 					 errmsg("not all privileges were granted")));
+ 	}
+ 	else
+ 	{
+ 		if (this_privileges == 0)
+ 			ereport(WARNING,
+ 					(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
+ 					 errmsg("no privileges could be revoked")));
+ 		else if (!all_privs && this_privileges != privileges)
+ 			ereport(WARNING,
+ 					(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
+ 					 errmsg("not all privileges could be revoked")));
+ 	}
+ 
+ 	return this_privileges;
+ }
+ 
  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)
  	{
  		Oid			relOid = lfirst_oid(cell);
  		Datum		aclDatum;
***************
*** 511,566 ****
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * If we found no grant options, consider whether to issue a hard
! 		 * error.  Per spec, having any privilege at all on the object will
! 		 * get you by here.
! 		 */
! 		if (avail_goptions == ACL_NO_RIGHTS)
! 		{
! 			if (pg_class_aclmask(relOid,
! 								 grantorId,
! 								 ACL_ALL_RIGHTS_RELATION | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_RELATION),
! 								 ACLMASK_ANY) == ACL_NO_RIGHTS)
! 				aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,
! 							   NameStr(pg_class_tuple->relname));
! 		}
! 
! 		/*
! 		 * Restrict the operation to what we can actually grant or revoke, and
! 		 * issue a warning if appropriate.	(For REVOKE this isn't quite what
! 		 * the spec says to do: the spec seems to want a warning only if no
! 		 * privilege bits actually change in the ACL. In practice that
! 		 * behavior seems much too noisy, as well as inconsistent with the
! 		 * GRANT case.)
  		 */
! 		this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! 		if (is_grant)
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("no privileges were granted")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("not all privileges were granted")));
! 		}
! 		else
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("no privileges could be revoked")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("not all privileges could be revoked")));
! 		}
  
  		/*
  		 * Generate new ACL.
--- 562,581 ----
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), istmt->privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * Restrict the privileges to what we can actually grant, and emit
! 		 * the standards-mandated warning and error messages.
  		 */
! 		this_privileges =
! 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
! 									 istmt->all_privs, istmt->privileges,
! 									 relOid, grantorId,
! 									 ACL_ALL_RIGHTS_RELATION, ACL_KIND_CLASS,
! 									 NameStr(pg_class_tuple->relname));
  
  		/*
  		 * Generate new ACL.
***************
*** 570,578 ****
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, is_grant,
! 									   grant_option, behavior,
! 									   grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
--- 585,593 ----
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! 									   istmt->grant_option, istmt->behavior,
! 									   istmt->grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 594,600 ****
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(RelationRelationId, relOid,
! 							  ownerId, is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
--- 609,615 ----
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(RelationRelationId, relOid,
! 							  ownerId, istmt->is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
***************
*** 610,628 ****
  }
  
  static void
! ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
! 				   AclMode privileges, List *grantees, bool grant_option,
! 				   DropBehavior behavior)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (all_privs && privileges == ACL_NO_RIGHTS)
! 		privileges = ACL_ALL_RIGHTS_DATABASE;
  
  	relation = heap_open(DatabaseRelationId, RowExclusiveLock);
  
! 	foreach (cell, objects)
  	{
  		Oid			datId = lfirst_oid(cell);
  		Form_pg_database pg_database_tuple;
--- 625,641 ----
  }
  
  static void
! ExecGrant_Database(InternalGrant *istmt)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! 		istmt->privileges = ACL_ALL_RIGHTS_DATABASE;
  
  	relation = heap_open(DatabaseRelationId, RowExclusiveLock);
  
! 	foreach (cell, istmt->objects)
  	{
  		Oid			datId = lfirst_oid(cell);
  		Form_pg_database pg_database_tuple;
***************
*** 674,729 ****
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * If we found no grant options, consider whether to issue a hard
! 		 * error.  Per spec, having any privilege at all on the object will
! 		 * get you by here.
! 		 */
! 		if (avail_goptions == ACL_NO_RIGHTS)
! 		{
! 			if (pg_database_aclmask(HeapTupleGetOid(tuple),
! 									grantorId,
! 									ACL_ALL_RIGHTS_DATABASE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_DATABASE),
! 									ACLMASK_ANY) == ACL_NO_RIGHTS)
! 				aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_DATABASE,
! 							   NameStr(pg_database_tuple->datname));
! 		}
! 
! 		/*
! 		 * Restrict the operation to what we can actually grant or revoke, and
! 		 * issue a warning if appropriate.	(For REVOKE this isn't quite what
! 		 * the spec says to do: the spec seems to want a warning only if no
! 		 * privilege bits actually change in the ACL. In practice that
! 		 * behavior seems much too noisy, as well as inconsistent with the
! 		 * GRANT case.)
  		 */
! 		this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! 		if (is_grant)
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("no privileges were granted")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("not all privileges were granted")));
! 		}
! 		else
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("no privileges could be revoked")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("not all privileges could be revoked")));
! 		}
  
  		/*
  		 * Generate new ACL.
--- 687,706 ----
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), istmt->privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * Restrict the privileges to what we can actually grant, and emit
! 		 * the standards-mandated warning and error messages.
  		 */
! 		this_privileges =
! 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
! 									 istmt->all_privs, istmt->privileges,
! 									 datId, grantorId, ACL_ALL_RIGHTS_DATABASE,
! 									 ACL_KIND_DATABASE,
! 									 NameStr(pg_database_tuple->datname));
  
  		/*
  		 * Generate new ACL.
***************
*** 733,741 ****
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, is_grant,
! 									   grant_option, behavior,
! 									   grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
--- 710,718 ----
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! 									   istmt->grant_option, istmt->behavior,
! 									   istmt->grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 758,764 ****
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
! 							  ownerId, is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
--- 735,741 ----
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
! 							  ownerId, istmt->is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
***************
*** 774,792 ****
  }
  
  static void
! ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
! 				   AclMode privileges, List *grantees, bool grant_option,
! 				   DropBehavior behavior)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (all_privs && privileges == ACL_NO_RIGHTS)
! 		privileges = ACL_ALL_RIGHTS_FUNCTION;
  
  	relation = heap_open(ProcedureRelationId, RowExclusiveLock);
  
! 	foreach (cell, objects)
  	{
  		Oid			funcId = lfirst_oid(cell);
  		Form_pg_proc pg_proc_tuple;
--- 751,767 ----
  }
  
  static void
! ExecGrant_Function(InternalGrant *istmt)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! 		istmt->privileges = ACL_ALL_RIGHTS_FUNCTION;
  
  	relation = heap_open(ProcedureRelationId, RowExclusiveLock);
  
! 	foreach (cell, istmt->objects)
  	{
  		Oid			funcId = lfirst_oid(cell);
  		Form_pg_proc pg_proc_tuple;
***************
*** 829,884 ****
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * If we found no grant options, consider whether to issue a hard
! 		 * error.  Per spec, having any privilege at all on the object will
! 		 * get you by here.
  		 */
! 		if (avail_goptions == ACL_NO_RIGHTS)
! 		{
! 			if (pg_proc_aclmask(funcId,
! 								grantorId,
! 								ACL_ALL_RIGHTS_FUNCTION | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_FUNCTION),
! 								ACLMASK_ANY) == ACL_NO_RIGHTS)
! 				aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_PROC,
! 							   NameStr(pg_proc_tuple->proname));
! 		}
! 
! 		/*
! 		 * Restrict the operation to what we can actually grant or revoke, and
! 		 * issue a warning if appropriate.	(For REVOKE this isn't quite what
! 		 * the spec says to do: the spec seems to want a warning only if no
! 		 * privilege bits actually change in the ACL. In practice that
! 		 * behavior seems much too noisy, as well as inconsistent with the
! 		 * GRANT case.)
! 		 */
! 		this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! 		if (is_grant)
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("no privileges were granted")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("not all privileges were granted")));
! 		}
! 		else
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("no privileges could be revoked")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("not all privileges could be revoked")));
! 		}
  
  		/*
  		 * Generate new ACL.
--- 804,824 ----
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), istmt->privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * Restrict the privileges to what we can actually grant, and emit
! 		 * the standards-mandated warning and error messages.
  		 */
! 		this_privileges =
! 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
! 									 istmt->all_privs, istmt->privileges,
! 									 funcId, grantorId,
! 									 ACL_ALL_RIGHTS_FUNCTION,
! 									 ACL_KIND_PROC,
! 									 NameStr(pg_proc_tuple->proname));
  
  		/*
  		 * Generate new ACL.
***************
*** 888,896 ****
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, is_grant,
! 									   grant_option, behavior,
! 									   grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
--- 828,836 ----
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! 									   istmt->grant_option, istmt->behavior,
! 									   istmt->grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 913,919 ****
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(ProcedureRelationId, funcId,	
! 							  ownerId, is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
--- 853,859 ----
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(ProcedureRelationId, funcId,	
! 							  ownerId, istmt->is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
***************
*** 929,949 ****
  }
  
  static void
! ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
! 				   AclMode privileges, List *grantees, bool grant_option,
! 				   DropBehavior behavior)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (all_privs && privileges == ACL_NO_RIGHTS)
! 		privileges = ACL_ALL_RIGHTS_LANGUAGE;
  
  	relation = heap_open(LanguageRelationId, RowExclusiveLock);
  
! 	foreach (cell, objects)
  	{
! 		Oid			langid = lfirst_oid(cell);
  		Form_pg_language pg_language_tuple;
  		Datum		aclDatum;
  		bool		isNull;
--- 869,887 ----
  }
  
  static void
! ExecGrant_Language(InternalGrant *istmt)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! 		istmt->privileges = ACL_ALL_RIGHTS_LANGUAGE;
  
  	relation = heap_open(LanguageRelationId, RowExclusiveLock);
  
! 	foreach (cell, istmt->objects)
  	{
! 		Oid			langId = lfirst_oid(cell);
  		Form_pg_language pg_language_tuple;
  		Datum		aclDatum;
  		bool		isNull;
***************
*** 964,973 ****
  		Oid		   *newmembers;
  
  		tuple = SearchSysCache(LANGOID,
! 							   ObjectIdGetDatum(langid),
  							   0, 0, 0);
  		if (!HeapTupleIsValid(tuple))
! 			elog(ERROR, "cache lookup failed for language %u", langid);
  
  		pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
  
--- 902,911 ----
  		Oid		   *newmembers;
  
  		tuple = SearchSysCache(LANGOID,
! 							   ObjectIdGetDatum(langId),
  							   0, 0, 0);
  		if (!HeapTupleIsValid(tuple))
! 			elog(ERROR, "cache lookup failed for language %u", langId);
  
  		pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
  
***************
*** 994,1049 ****
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * If we found no grant options, consider whether to issue a hard
! 		 * error.  Per spec, having any privilege at all on the object will
! 		 * get you by here.
  		 */
! 		if (avail_goptions == ACL_NO_RIGHTS)
! 		{
! 			if (pg_language_aclmask(HeapTupleGetOid(tuple),
! 									grantorId,
! 									ACL_ALL_RIGHTS_LANGUAGE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_LANGUAGE),
! 									ACLMASK_ANY) == ACL_NO_RIGHTS)
! 				aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
! 							   NameStr(pg_language_tuple->lanname));
! 		}
! 
! 		/*
! 		 * Restrict the operation to what we can actually grant or revoke, and
! 		 * issue a warning if appropriate.	(For REVOKE this isn't quite what
! 		 * the spec says to do: the spec seems to want a warning only if no
! 		 * privilege bits actually change in the ACL. In practice that
! 		 * behavior seems much too noisy, as well as inconsistent with the
! 		 * GRANT case.)
! 		 */
! 		this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! 		if (is_grant)
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("no privileges were granted")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("not all privileges were granted")));
! 		}
! 		else
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("no privileges could be revoked")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("not all privileges could be revoked")));
! 		}
  
  		/*
  		 * Generate new ACL.
--- 932,952 ----
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), istmt->privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * Restrict the privileges to what we can actually grant, and emit
! 		 * the standards-mandated warning and error messages.
  		 */
! 		this_privileges =
! 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
! 									 istmt->all_privs, istmt->privileges,
! 									 langId, grantorId,
! 									 ACL_ALL_RIGHTS_LANGUAGE,
! 									 ACL_KIND_LANGUAGE,
! 									 NameStr(pg_language_tuple->lanname));
  
  		/*
  		 * Generate new ACL.
***************
*** 1053,1061 ****
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, is_grant,
! 									   grant_option, behavior,
! 									   grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
--- 956,964 ----
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! 									   istmt->grant_option, istmt->behavior,
! 									   istmt->grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 1078,1084 ****
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
! 							  ownerId, is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
--- 981,987 ----
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
! 							  ownerId, istmt->is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
***************
*** 1094,1112 ****
  }
  
  static void
! ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
!  					AclMode privileges, List *grantees, bool grant_option,
!  					DropBehavior behavior)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (all_privs && privileges == ACL_NO_RIGHTS)
! 		privileges = ACL_ALL_RIGHTS_NAMESPACE;
  
  	relation = heap_open(NamespaceRelationId, RowExclusiveLock);
  
! 	foreach(cell, objects)
  	{
  		Oid			nspid = lfirst_oid(cell);
  		Form_pg_namespace pg_namespace_tuple;
--- 997,1013 ----
  }
  
  static void
! ExecGrant_Namespace(InternalGrant *istmt)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! 		istmt->privileges = ACL_ALL_RIGHTS_NAMESPACE;
  
  	relation = heap_open(NamespaceRelationId, RowExclusiveLock);
  
! 	foreach(cell, istmt->objects)
  	{
  		Oid			nspid = lfirst_oid(cell);
  		Form_pg_namespace pg_namespace_tuple;
***************
*** 1150,1205 ****
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * If we found no grant options, consider whether to issue a hard
! 		 * error.  Per spec, having any privilege at all on the object will
! 		 * get you by here.
  		 */
! 		if (avail_goptions == ACL_NO_RIGHTS)
! 		{
! 			if (pg_namespace_aclmask(HeapTupleGetOid(tuple),
! 									 grantorId,
! 									 ACL_ALL_RIGHTS_NAMESPACE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_NAMESPACE),
! 									 ACLMASK_ANY) == ACL_NO_RIGHTS)
! 				aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_NAMESPACE,
! 							   NameStr(pg_namespace_tuple->nspname));
! 		}
! 
! 		/*
! 		 * Restrict the operation to what we can actually grant or revoke, and
! 		 * issue a warning if appropriate.	(For REVOKE this isn't quite what
! 		 * the spec says to do: the spec seems to want a warning only if no
! 		 * privilege bits actually change in the ACL. In practice that
! 		 * behavior seems much too noisy, as well as inconsistent with the
! 		 * GRANT case.)
! 		 */
! 		this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! 		if (is_grant)
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("no privileges were granted")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("not all privileges were granted")));
! 		}
! 		else
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("no privileges could be revoked")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("not all privileges could be revoked")));
! 		}
  
  		/*
  		 * Generate new ACL.
--- 1051,1071 ----
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), istmt->privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * Restrict the privileges to what we can actually grant, and emit
! 		 * the standards-mandated warning and error messages.
  		 */
! 		this_privileges =
! 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
! 									 istmt->all_privs, istmt->privileges,
! 									 nspid, grantorId,
! 									 ACL_ALL_RIGHTS_NAMESPACE,
! 									 ACL_KIND_NAMESPACE,
! 									 NameStr(pg_namespace_tuple->nspname));
  
  		/*
  		 * Generate new ACL.
***************
*** 1209,1217 ****
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, is_grant,
! 									   grant_option, behavior,
! 									   grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
--- 1075,1083 ----
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! 									   istmt->grant_option, istmt->behavior,
! 									   istmt->grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 1234,1240 ****
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
! 							  ownerId, is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
--- 1100,1106 ----
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
! 							  ownerId, istmt->is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
***************
*** 1250,1268 ****
  }
  
  static void
! ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
! 					 AclMode privileges, List *grantees, bool grant_option,
! 					 DropBehavior behavior)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (all_privs && privileges == ACL_NO_RIGHTS)
! 		privileges = ACL_ALL_RIGHTS_TABLESPACE;
  
  	relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
  
! 	foreach(cell, objects)
  	{
  		Oid			tblId = lfirst_oid(cell);
  		Form_pg_tablespace pg_tablespace_tuple;
--- 1116,1132 ----
  }
  
  static void
! ExecGrant_Tablespace(InternalGrant *istmt)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! 		istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE;
  
  	relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
  
! 	foreach(cell, istmt->objects)
  	{
  		Oid			tblId = lfirst_oid(cell);
  		Form_pg_tablespace pg_tablespace_tuple;
***************
*** 1312,1367 ****
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * If we found no grant options, consider whether to issue a hard
! 		 * error.  Per spec, having any privilege at all on the object will
! 		 * get you by here.
! 		 */
! 		if (avail_goptions == ACL_NO_RIGHTS)
! 		{
! 			if (pg_tablespace_aclmask(HeapTupleGetOid(tuple),
! 									  grantorId,
! 									  ACL_ALL_RIGHTS_TABLESPACE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_TABLESPACE),
! 									  ACLMASK_ANY) == ACL_NO_RIGHTS)
! 				aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE,
! 							   NameStr(pg_tablespace_tuple->spcname));
! 		}
! 
! 		/*
! 		 * Restrict the operation to what we can actually grant or revoke, and
! 		 * issue a warning if appropriate.	(For REVOKE this isn't quite what
! 		 * the spec says to do: the spec seems to want a warning only if no
! 		 * privilege bits actually change in the ACL. In practice that
! 		 * behavior seems much too noisy, as well as inconsistent with the
! 		 * GRANT case.)
  		 */
! 		this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! 		if (is_grant)
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("no privileges were granted")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("not all privileges were granted")));
! 		}
! 		else
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("no privileges could be revoked")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("not all privileges could be revoked")));
! 		}
  
  		/*
  		 * Generate new ACL.
--- 1176,1196 ----
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), istmt->privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * Restrict the privileges to what we can actually grant, and emit
! 		 * the standards-mandated warning and error messages.
  		 */
! 		this_privileges =
! 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
! 									 istmt->all_privs, istmt->privileges,
! 									 tblId, grantorId,
! 									 ACL_ALL_RIGHTS_TABLESPACE,
! 									 ACL_KIND_TABLESPACE,
! 									 NameStr(pg_tablespace_tuple->spcname));
  
  		/*
  		 * Generate new ACL.
***************
*** 1371,1379 ****
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, is_grant,
! 									   grant_option, behavior,
! 									   grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
--- 1200,1208 ----
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! 									   istmt->grant_option, istmt->behavior,
! 									   istmt->grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 1396,1402 ****
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(TableSpaceRelationId, tblId,
! 							  ownerId, is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
--- 1225,1231 ----
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(TableSpaceRelationId, tblId,
! 							  ownerId, istmt->is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
Index: src/backend/catalog/pg_shdepend.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/pg_shdepend.c,v
retrieving revision 1.4
diff -c -r1.4 pg_shdepend.c
*** src/backend/catalog/pg_shdepend.c	21 Nov 2005 12:49:30 -0000	1.4
--- src/backend/catalog/pg_shdepend.c	21 Nov 2005 15:08:16 -0000
***************
*** 1122,1127 ****
--- 1122,1128 ----
  			{
  				ObjectAddress	obj;
  				GrantObjectType	objtype;
+ 				InternalGrant	istmt;
  
  				/* Shouldn't happen */
  				case SHARED_DEPENDENCY_PIN:
***************
*** 1132,1153 ****
  					switch (sdepForm->classid)
  					{
  						case RelationRelationId:
! 							objtype = ACL_OBJECT_RELATION;
  							break;
  						case DatabaseRelationId:
! 							objtype = ACL_OBJECT_DATABASE;
  							break;
  						case ProcedureRelationId:
! 							objtype = ACL_OBJECT_FUNCTION;
  							break;
  						case LanguageRelationId:
! 							objtype = ACL_OBJECT_LANGUAGE;
  							break;
  						case NamespaceRelationId:
! 							objtype = ACL_OBJECT_NAMESPACE;
  							break;
  						case TableSpaceRelationId:
! 							objtype = ACL_OBJECT_TABLESPACE;
  							break;
  						default:
  							elog(ERROR, "unexpected object type %d",
--- 1133,1154 ----
  					switch (sdepForm->classid)
  					{
  						case RelationRelationId:
! 							istmt.objtype = ACL_OBJECT_RELATION;
  							break;
  						case DatabaseRelationId:
! 							istmt.objtype = ACL_OBJECT_DATABASE;
  							break;
  						case ProcedureRelationId:
! 							istmt.objtype = ACL_OBJECT_FUNCTION;
  							break;
  						case LanguageRelationId:
! 							istmt.objtype = ACL_OBJECT_LANGUAGE;
  							break;
  						case NamespaceRelationId:
! 							istmt.objtype = ACL_OBJECT_NAMESPACE;
  							break;
  						case TableSpaceRelationId:
! 							istmt.objtype = ACL_OBJECT_TABLESPACE;
  							break;
  						default:
  							elog(ERROR, "unexpected object type %d",
***************
*** 1156,1166 ****
  							objtype = (GrantObjectType) 0;
  							break;
  					}
  
! 					ExecGrantStmt_oids(false, objtype,
! 									   list_make1_oid(sdepForm->objid), true,
! 									   ACL_NO_RIGHTS, list_make1_oid(roleid),
! 									   false, DROP_CASCADE);
  					break;
  				case SHARED_DEPENDENCY_OWNER:
  					/*
--- 1157,1171 ----
  							objtype = (GrantObjectType) 0;
  							break;
  					}
+ 					istmt.is_grant = false;
+ 					istmt.objects = list_make1_oid(sdepForm->objid);
+ 					istmt.all_privs = true;
+ 					istmt.privileges = ACL_NO_RIGHTS;
+ 					istmt.grantees = list_make1_oid(roleid);
+ 					istmt.grant_option = false;
+ 					istmt.behavior = DROP_CASCADE;
  
! 					ExecGrantStmt_oids(&istmt);
  					break;
  				case SHARED_DEPENDENCY_OWNER:
  					/*
Index: src/include/utils/acl.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/utils/acl.h,v
retrieving revision 1.89
diff -c -r1.89 acl.h
*** src/include/utils/acl.h	21 Nov 2005 12:49:33 -0000	1.89
--- src/include/utils/acl.h	21 Nov 2005 14:32:59 -0000
***************
*** 182,187 ****
--- 182,207 ----
  } AclObjectKind;
  
  /*
+  * The information about one Grant/Revoke statement, in internal format: object
+  * and grantees names have been turned into Oids, the privilege list is an
+  * AclMode bitmask.  If 'privileges' is ACL_NO_RIGHTS (the 0 value) and
+  * all_privs is true, it will be internally turned into the right kind of
+  * ACL_ALL_RIGHTS_*, depending on the object type (NB - this will modify the
+  * InternalGrant struct!)
+  */
+ typedef struct
+ {
+ 	bool    is_grant;
+ 	GrantObjectType objtype;
+ 	List   *objects;
+ 	bool    all_privs;
+ 	AclMode privileges;
+ 	List   *grantees;
+ 	bool    grant_option;
+ 	DropBehavior behavior;
+ } InternalGrant;
+ 
+ /*
   * routines used internally
   */
  extern Acl *acldefault(GrantObjectType objtype, Oid ownerId);
***************
*** 221,229 ****
   * prototypes for functions in aclchk.c
   */
  extern void ExecuteGrantStmt(GrantStmt *stmt);
! extern void ExecGrantStmt_oids(bool is_grant, GrantObjectType objtype,
! 				   List *objects, bool all_privs, AclMode privileges,
! 				   List *grantees, bool grant_option, DropBehavior behavior);
  
  extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid,
  				 AclMode mask, AclMaskHow how);
--- 241,247 ----
   * prototypes for functions in aclchk.c
   */
  extern void ExecuteGrantStmt(GrantStmt *stmt);
! extern void ExecGrantStmt_oids(InternalGrant *istmt);
  
  extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid,
  				 AclMode mask, AclMaskHow how);


Attachments:

  [text/plain] aclchk-refactor-1.patch (44.2K, 2-aclchk-refactor-1.patch)
  download | inline diff:
Index: src/backend/catalog/aclchk.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/aclchk.c,v
retrieving revision 1.121
diff -c -r1.121 aclchk.c
*** src/backend/catalog/aclchk.c	21 Nov 2005 12:49:30 -0000	1.121
--- src/backend/catalog/aclchk.c	21 Nov 2005 15:05:19 -0000
***************
*** 42,69 ****
  #include "utils/syscache.h"
  
  
! static void ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
! 				   AclMode privileges, List *grantees, bool grant_option,
! 				   DropBehavior behavior);
! static void ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
! 				   AclMode privileges, List *grantees, bool grant_option,
! 				   DropBehavior behavior);
! static void ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
! 				   AclMode privileges, List *grantees, bool grant_option,
! 				   DropBehavior behavior);
! static void ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
! 				   AclMode privileges, List *grantees, bool grant_option,
! 				   DropBehavior behavior);
! static void ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
! 					AclMode privileges, List *grantees, bool grant_option,
! 					DropBehavior behavior);
! static void ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
! 					 AclMode privileges, List *grantees, bool grant_option,
! 					 DropBehavior behavior);
! static List *objectNamesToOids(GrantObjectType objtype, List *objnames);
  
  static AclMode string_to_privilege(const char *privname);
  static const char *privilege_to_string(AclMode privilege);
  
  
  #ifdef ACLDEBUG
--- 42,62 ----
  #include "utils/syscache.h"
  
  
! static void ExecGrant_Relation(InternalGrant *grantStmt);
! static void ExecGrant_Database(InternalGrant *grantStmt);
! static void ExecGrant_Function(InternalGrant *grantStmt);
! static void ExecGrant_Language(InternalGrant *grantStmt);
! static void ExecGrant_Namespace(InternalGrant *grantStmt);
! static void ExecGrant_Tablespace(InternalGrant *grantStmt);
  
+ static List *objectNamesToOids(GrantObjectType objtype, List *objnames);
  static AclMode string_to_privilege(const char *privname);
  static const char *privilege_to_string(AclMode privilege);
+ static AclMode restrict_and_check_grant(bool is_grant, AclMode avail_goptions,
+ 										bool all_privs, AclMode privileges,
+ 										Oid objectId, Oid grantorId,
+ 										AclMode whole_mask,
+ 										AclObjectKind objkind, char *objname);
  
  
  #ifdef ACLDEBUG
***************
*** 160,172 ****
  void
  ExecuteGrantStmt(GrantStmt *stmt)
  {
! 	List	   *objects;
! 	List	   *grantees = NIL;
! 	AclMode		privileges;
  	ListCell   *cell;
! 	bool		all_privs;
! 	AclMode all_privileges = (AclMode) 0;
! 	char	*errormsg = NULL;
  
  	/*
  	 * Convert the PrivGrantee list into an Oid list.  Note that at this point
--- 153,174 ----
  void
  ExecuteGrantStmt(GrantStmt *stmt)
  {
! 	InternalGrant istmt;
  	ListCell   *cell;
! 	char	   *errormsg;
! 	AclMode		all_privileges;
! 
! 	/*
! 	 * Turn the regular GrantStmt into the InternalGrant form.
! 	 */
! 	istmt.is_grant = stmt->is_grant;
! 	istmt.objtype = stmt->objtype;
! 	istmt.objects = objectNamesToOids(stmt->objtype, stmt->objects);
! 	/* all_privs to be filled below */
! 	/* privileges to be filled below */
! 	/* grantees to be filled below */
! 	istmt.grant_option = stmt->grant_option;
! 	istmt.behavior = stmt->behavior;
  
  	/*
  	 * Convert the PrivGrantee list into an Oid list.  Note that at this point
***************
*** 180,194 ****
  		PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
  
  		if (grantee->rolname == NULL)
! 			grantees = lappend_oid(grantees, ACL_ID_PUBLIC);
  		else
! 			grantees = lappend_oid(grantees,
! 								   get_roleid_checked(grantee->rolname));
  	}
  
  	/*
! 	 * Convert stmt->privileges, a textual list, into an AclMode bitmask
! 	 * appropiate for the given object class.
  	 */
  	switch (stmt->objtype)
  	{
--- 182,196 ----
  		PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
  
  		if (grantee->rolname == NULL)
! 			istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC);
  		else
! 			istmt.grantees =
! 				lappend_oid(istmt.grantees,
! 							get_roleid_checked(grantee->rolname));
  	}
  
  	/*
! 	 * Convert stmt->privileges, a textual list, into an AclMode bitmask.
  	 */
  	switch (stmt->objtype)
  	{
***************
*** 217,235 ****
  			errormsg = _("invalid privilege type %s for tablespace");
  			break;
  		default:
  			elog(ERROR, "unrecognized GrantStmt.objtype: %d",
  				 (int) stmt->objtype);
  	}
  
  	if (stmt->privileges == NIL)
  	{
! 		all_privs = true;
! 		privileges = all_privileges;
  	}
  	else
  	{
! 		all_privs = false;
! 		privileges = ACL_NO_RIGHTS;
  		foreach(cell, stmt->privileges)
  		{
  			char	   *privname = strVal(lfirst(cell));
--- 219,244 ----
  			errormsg = _("invalid privilege type %s for tablespace");
  			break;
  		default:
+ 			/* keep compiler quiet */
+ 			all_privileges = ACL_NO_RIGHTS;
+ 			errormsg = NULL;
  			elog(ERROR, "unrecognized GrantStmt.objtype: %d",
  				 (int) stmt->objtype);
  	}
  
  	if (stmt->privileges == NIL)
  	{
! 		istmt.all_privs = true;
! 		/*
! 		 * will be turned into ACL_ALL_RIGHTS_* by the internal routines
! 		 * depending on the object type
! 		 */
! 		istmt.privileges = ACL_NO_RIGHTS;
  	}
  	else
  	{
! 		istmt.all_privs = false;
! 		istmt.privileges = ACL_NO_RIGHTS;
  		foreach(cell, stmt->privileges)
  		{
  			char	   *privname = strVal(lfirst(cell));
***************
*** 241,301 ****
  						 errmsg(errormsg,
  								privilege_to_string(priv))));
  
! 			privileges |= priv;
  		}
  	}
  
! 	/* Turn the list of object names into an Oid list */
! 	objects = objectNamesToOids(stmt->objtype, stmt->objects);
! 
! 	ExecGrantStmt_oids(stmt->is_grant, stmt->objtype, objects, all_privs,
! 					   privileges, grantees, stmt->grant_option,
! 					   stmt->behavior);
  }
  
  /*
   * ExecGrantStmt_oids
   *
!  * "Internal" entrypoint for granting and revoking privileges.  The arguments
!  * it receives are lists of Oids or have been otherwise converted from text
!  * format to internal format.
   */
  void
! ExecGrantStmt_oids(bool is_grant, GrantObjectType objtype, List *objects,
! 				   bool all_privs, AclMode privileges, List *grantees,
! 				   bool grant_option, DropBehavior behavior)
  {
! 	switch (objtype)
  	{
  		case ACL_OBJECT_RELATION:
! 			ExecGrant_Relation(is_grant, objects, all_privs, privileges,
! 							   grantees, grant_option, behavior);
  			break;
  		case ACL_OBJECT_DATABASE:
! 			ExecGrant_Database(is_grant, objects, all_privs, privileges,
! 							   grantees, grant_option, behavior);
  			break;
  		case ACL_OBJECT_FUNCTION:
! 			ExecGrant_Function(is_grant, objects, all_privs, privileges,
! 							   grantees, grant_option, behavior);
  			break;
  		case ACL_OBJECT_LANGUAGE:
! 			ExecGrant_Language(is_grant, objects, all_privs, privileges,
! 							   grantees, grant_option, behavior);
  			break;
  		case ACL_OBJECT_NAMESPACE:
! 			ExecGrant_Namespace(is_grant, objects, all_privs,
! 								privileges, grantees, grant_option,
! 								behavior);
  			break;
  		case ACL_OBJECT_TABLESPACE:
! 			ExecGrant_Tablespace(is_grant, objects, all_privs,
! 								 privileges, grantees, grant_option,
! 								 behavior);
  			break;
  		default:
  			elog(ERROR, "unrecognized GrantStmt.objtype: %d",
! 				 (int) objtype);
  	}
  }
  
--- 250,293 ----
  						 errmsg(errormsg,
  								privilege_to_string(priv))));
  
! 			istmt.privileges |= priv;
  		}
  	}
  
! 	ExecGrantStmt_oids(&istmt);
  }
  
  /*
   * ExecGrantStmt_oids
   *
!  * "Internal" entrypoint for granting and revoking privileges.
   */
  void
! ExecGrantStmt_oids(InternalGrant *istmt)
  {
! 	switch (istmt->objtype)
  	{
  		case ACL_OBJECT_RELATION:
! 			ExecGrant_Relation(istmt);
  			break;
  		case ACL_OBJECT_DATABASE:
! 			ExecGrant_Database(istmt);
  			break;
  		case ACL_OBJECT_FUNCTION:
! 			ExecGrant_Function(istmt);
  			break;
  		case ACL_OBJECT_LANGUAGE:
! 			ExecGrant_Language(istmt);
  			break;
  		case ACL_OBJECT_NAMESPACE:
! 			ExecGrant_Namespace(istmt);
  			break;
  		case ACL_OBJECT_TABLESPACE:
! 			ExecGrant_Tablespace(istmt);
  			break;
  		default:
  			elog(ERROR, "unrecognized GrantStmt.objtype: %d",
! 				 (int) istmt->objtype);
  	}
  }
  
***************
*** 443,462 ****
  	return objects;
  }
  
  static void
! ExecGrant_Relation(bool is_grant, List *objects, bool all_privs,
! 				   AclMode privileges, List *grantees, bool grant_option,
! 				   DropBehavior behavior)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (all_privs && privileges == ACL_NO_RIGHTS)
! 		privileges = ACL_ALL_RIGHTS_RELATION;
  
  	relation = heap_open(RelationRelationId, RowExclusiveLock);
  
! 	foreach (cell, objects)
  	{
  		Oid			relOid = lfirst_oid(cell);
  		Datum		aclDatum;
--- 435,513 ----
  	return objects;
  }
  
+ /*
+  * Restrict the privileges to what we can actually grant, and emit
+  * the standards-mandated warning and error messages.
+  */
+ static AclMode
+ restrict_and_check_grant(bool is_grant, AclMode avail_goptions, bool all_privs,
+ 						 AclMode privileges, Oid objectId, Oid grantorId,
+ 						 AclMode whole_mask, AclObjectKind objkind,
+ 						 char *objname)
+ {
+ 	AclMode	this_privileges;
+ 
+ 	/*
+ 	 * If we found no grant options, consider whether to issue a hard
+ 	 * error.  Per spec, having any privilege at all on the object will
+ 	 * get you by here.
+ 	 */
+ 	if (avail_goptions == ACL_NO_RIGHTS)
+ 	{
+ 		if (pg_class_aclmask(objectId,
+ 							 grantorId,
+ 							 whole_mask | ACL_GRANT_OPTION_FOR(whole_mask),
+ 							 ACLMASK_ANY) == ACL_NO_RIGHTS)
+ 			aclcheck_error(ACLCHECK_NO_PRIV, objkind, objname);
+ 	}
+ 
+ 	/*
+ 	 * Restrict the operation to what we can actually grant or revoke, and
+ 	 * issue a warning if appropriate.	(For REVOKE this isn't quite what
+ 	 * the spec says to do: the spec seems to want a warning only if no
+ 	 * privilege bits actually change in the ACL. In practice that
+ 	 * behavior seems much too noisy, as well as inconsistent with the
+ 	 * GRANT case.)
+ 	 */
+ 	this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
+ 	if (is_grant)
+ 	{
+ 		if (this_privileges == 0)
+ 			ereport(WARNING,
+ 					(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
+ 					 errmsg("no privileges were granted")));
+ 		else if (!all_privs && this_privileges != privileges)
+ 			ereport(WARNING,
+ 					(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
+ 					 errmsg("not all privileges were granted")));
+ 	}
+ 	else
+ 	{
+ 		if (this_privileges == 0)
+ 			ereport(WARNING,
+ 					(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
+ 					 errmsg("no privileges could be revoked")));
+ 		else if (!all_privs && this_privileges != privileges)
+ 			ereport(WARNING,
+ 					(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
+ 					 errmsg("not all privileges could be revoked")));
+ 	}
+ 
+ 	return this_privileges;
+ }
+ 
  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)
  	{
  		Oid			relOid = lfirst_oid(cell);
  		Datum		aclDatum;
***************
*** 511,566 ****
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * If we found no grant options, consider whether to issue a hard
! 		 * error.  Per spec, having any privilege at all on the object will
! 		 * get you by here.
! 		 */
! 		if (avail_goptions == ACL_NO_RIGHTS)
! 		{
! 			if (pg_class_aclmask(relOid,
! 								 grantorId,
! 								 ACL_ALL_RIGHTS_RELATION | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_RELATION),
! 								 ACLMASK_ANY) == ACL_NO_RIGHTS)
! 				aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,
! 							   NameStr(pg_class_tuple->relname));
! 		}
! 
! 		/*
! 		 * Restrict the operation to what we can actually grant or revoke, and
! 		 * issue a warning if appropriate.	(For REVOKE this isn't quite what
! 		 * the spec says to do: the spec seems to want a warning only if no
! 		 * privilege bits actually change in the ACL. In practice that
! 		 * behavior seems much too noisy, as well as inconsistent with the
! 		 * GRANT case.)
  		 */
! 		this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! 		if (is_grant)
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("no privileges were granted")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("not all privileges were granted")));
! 		}
! 		else
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("no privileges could be revoked")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("not all privileges could be revoked")));
! 		}
  
  		/*
  		 * Generate new ACL.
--- 562,581 ----
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), istmt->privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * Restrict the privileges to what we can actually grant, and emit
! 		 * the standards-mandated warning and error messages.
  		 */
! 		this_privileges =
! 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
! 									 istmt->all_privs, istmt->privileges,
! 									 relOid, grantorId,
! 									 ACL_ALL_RIGHTS_RELATION, ACL_KIND_CLASS,
! 									 NameStr(pg_class_tuple->relname));
  
  		/*
  		 * Generate new ACL.
***************
*** 570,578 ****
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, is_grant,
! 									   grant_option, behavior,
! 									   grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
--- 585,593 ----
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! 									   istmt->grant_option, istmt->behavior,
! 									   istmt->grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 594,600 ****
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(RelationRelationId, relOid,
! 							  ownerId, is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
--- 609,615 ----
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(RelationRelationId, relOid,
! 							  ownerId, istmt->is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
***************
*** 610,628 ****
  }
  
  static void
! ExecGrant_Database(bool is_grant, List *objects, bool all_privs,
! 				   AclMode privileges, List *grantees, bool grant_option,
! 				   DropBehavior behavior)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (all_privs && privileges == ACL_NO_RIGHTS)
! 		privileges = ACL_ALL_RIGHTS_DATABASE;
  
  	relation = heap_open(DatabaseRelationId, RowExclusiveLock);
  
! 	foreach (cell, objects)
  	{
  		Oid			datId = lfirst_oid(cell);
  		Form_pg_database pg_database_tuple;
--- 625,641 ----
  }
  
  static void
! ExecGrant_Database(InternalGrant *istmt)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! 		istmt->privileges = ACL_ALL_RIGHTS_DATABASE;
  
  	relation = heap_open(DatabaseRelationId, RowExclusiveLock);
  
! 	foreach (cell, istmt->objects)
  	{
  		Oid			datId = lfirst_oid(cell);
  		Form_pg_database pg_database_tuple;
***************
*** 674,729 ****
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * If we found no grant options, consider whether to issue a hard
! 		 * error.  Per spec, having any privilege at all on the object will
! 		 * get you by here.
! 		 */
! 		if (avail_goptions == ACL_NO_RIGHTS)
! 		{
! 			if (pg_database_aclmask(HeapTupleGetOid(tuple),
! 									grantorId,
! 									ACL_ALL_RIGHTS_DATABASE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_DATABASE),
! 									ACLMASK_ANY) == ACL_NO_RIGHTS)
! 				aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_DATABASE,
! 							   NameStr(pg_database_tuple->datname));
! 		}
! 
! 		/*
! 		 * Restrict the operation to what we can actually grant or revoke, and
! 		 * issue a warning if appropriate.	(For REVOKE this isn't quite what
! 		 * the spec says to do: the spec seems to want a warning only if no
! 		 * privilege bits actually change in the ACL. In practice that
! 		 * behavior seems much too noisy, as well as inconsistent with the
! 		 * GRANT case.)
  		 */
! 		this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! 		if (is_grant)
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("no privileges were granted")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("not all privileges were granted")));
! 		}
! 		else
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("no privileges could be revoked")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("not all privileges could be revoked")));
! 		}
  
  		/*
  		 * Generate new ACL.
--- 687,706 ----
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), istmt->privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * Restrict the privileges to what we can actually grant, and emit
! 		 * the standards-mandated warning and error messages.
  		 */
! 		this_privileges =
! 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
! 									 istmt->all_privs, istmt->privileges,
! 									 datId, grantorId, ACL_ALL_RIGHTS_DATABASE,
! 									 ACL_KIND_DATABASE,
! 									 NameStr(pg_database_tuple->datname));
  
  		/*
  		 * Generate new ACL.
***************
*** 733,741 ****
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, is_grant,
! 									   grant_option, behavior,
! 									   grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
--- 710,718 ----
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! 									   istmt->grant_option, istmt->behavior,
! 									   istmt->grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 758,764 ****
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
! 							  ownerId, is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
--- 735,741 ----
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(DatabaseRelationId, HeapTupleGetOid(tuple),
! 							  ownerId, istmt->is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
***************
*** 774,792 ****
  }
  
  static void
! ExecGrant_Function(bool is_grant, List *objects, bool all_privs,
! 				   AclMode privileges, List *grantees, bool grant_option,
! 				   DropBehavior behavior)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (all_privs && privileges == ACL_NO_RIGHTS)
! 		privileges = ACL_ALL_RIGHTS_FUNCTION;
  
  	relation = heap_open(ProcedureRelationId, RowExclusiveLock);
  
! 	foreach (cell, objects)
  	{
  		Oid			funcId = lfirst_oid(cell);
  		Form_pg_proc pg_proc_tuple;
--- 751,767 ----
  }
  
  static void
! ExecGrant_Function(InternalGrant *istmt)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! 		istmt->privileges = ACL_ALL_RIGHTS_FUNCTION;
  
  	relation = heap_open(ProcedureRelationId, RowExclusiveLock);
  
! 	foreach (cell, istmt->objects)
  	{
  		Oid			funcId = lfirst_oid(cell);
  		Form_pg_proc pg_proc_tuple;
***************
*** 829,884 ****
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * If we found no grant options, consider whether to issue a hard
! 		 * error.  Per spec, having any privilege at all on the object will
! 		 * get you by here.
  		 */
! 		if (avail_goptions == ACL_NO_RIGHTS)
! 		{
! 			if (pg_proc_aclmask(funcId,
! 								grantorId,
! 								ACL_ALL_RIGHTS_FUNCTION | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_FUNCTION),
! 								ACLMASK_ANY) == ACL_NO_RIGHTS)
! 				aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_PROC,
! 							   NameStr(pg_proc_tuple->proname));
! 		}
! 
! 		/*
! 		 * Restrict the operation to what we can actually grant or revoke, and
! 		 * issue a warning if appropriate.	(For REVOKE this isn't quite what
! 		 * the spec says to do: the spec seems to want a warning only if no
! 		 * privilege bits actually change in the ACL. In practice that
! 		 * behavior seems much too noisy, as well as inconsistent with the
! 		 * GRANT case.)
! 		 */
! 		this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! 		if (is_grant)
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("no privileges were granted")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("not all privileges were granted")));
! 		}
! 		else
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("no privileges could be revoked")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("not all privileges could be revoked")));
! 		}
  
  		/*
  		 * Generate new ACL.
--- 804,824 ----
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), istmt->privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * Restrict the privileges to what we can actually grant, and emit
! 		 * the standards-mandated warning and error messages.
  		 */
! 		this_privileges =
! 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
! 									 istmt->all_privs, istmt->privileges,
! 									 funcId, grantorId,
! 									 ACL_ALL_RIGHTS_FUNCTION,
! 									 ACL_KIND_PROC,
! 									 NameStr(pg_proc_tuple->proname));
  
  		/*
  		 * Generate new ACL.
***************
*** 888,896 ****
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, is_grant,
! 									   grant_option, behavior,
! 									   grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
--- 828,836 ----
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! 									   istmt->grant_option, istmt->behavior,
! 									   istmt->grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 913,919 ****
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(ProcedureRelationId, funcId,	
! 							  ownerId, is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
--- 853,859 ----
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(ProcedureRelationId, funcId,	
! 							  ownerId, istmt->is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
***************
*** 929,949 ****
  }
  
  static void
! ExecGrant_Language(bool is_grant, List *objects, bool all_privs,
! 				   AclMode privileges, List *grantees, bool grant_option,
! 				   DropBehavior behavior)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (all_privs && privileges == ACL_NO_RIGHTS)
! 		privileges = ACL_ALL_RIGHTS_LANGUAGE;
  
  	relation = heap_open(LanguageRelationId, RowExclusiveLock);
  
! 	foreach (cell, objects)
  	{
! 		Oid			langid = lfirst_oid(cell);
  		Form_pg_language pg_language_tuple;
  		Datum		aclDatum;
  		bool		isNull;
--- 869,887 ----
  }
  
  static void
! ExecGrant_Language(InternalGrant *istmt)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! 		istmt->privileges = ACL_ALL_RIGHTS_LANGUAGE;
  
  	relation = heap_open(LanguageRelationId, RowExclusiveLock);
  
! 	foreach (cell, istmt->objects)
  	{
! 		Oid			langId = lfirst_oid(cell);
  		Form_pg_language pg_language_tuple;
  		Datum		aclDatum;
  		bool		isNull;
***************
*** 964,973 ****
  		Oid		   *newmembers;
  
  		tuple = SearchSysCache(LANGOID,
! 							   ObjectIdGetDatum(langid),
  							   0, 0, 0);
  		if (!HeapTupleIsValid(tuple))
! 			elog(ERROR, "cache lookup failed for language %u", langid);
  
  		pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
  
--- 902,911 ----
  		Oid		   *newmembers;
  
  		tuple = SearchSysCache(LANGOID,
! 							   ObjectIdGetDatum(langId),
  							   0, 0, 0);
  		if (!HeapTupleIsValid(tuple))
! 			elog(ERROR, "cache lookup failed for language %u", langId);
  
  		pg_language_tuple = (Form_pg_language) GETSTRUCT(tuple);
  
***************
*** 994,1049 ****
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * If we found no grant options, consider whether to issue a hard
! 		 * error.  Per spec, having any privilege at all on the object will
! 		 * get you by here.
  		 */
! 		if (avail_goptions == ACL_NO_RIGHTS)
! 		{
! 			if (pg_language_aclmask(HeapTupleGetOid(tuple),
! 									grantorId,
! 									ACL_ALL_RIGHTS_LANGUAGE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_LANGUAGE),
! 									ACLMASK_ANY) == ACL_NO_RIGHTS)
! 				aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_LANGUAGE,
! 							   NameStr(pg_language_tuple->lanname));
! 		}
! 
! 		/*
! 		 * Restrict the operation to what we can actually grant or revoke, and
! 		 * issue a warning if appropriate.	(For REVOKE this isn't quite what
! 		 * the spec says to do: the spec seems to want a warning only if no
! 		 * privilege bits actually change in the ACL. In practice that
! 		 * behavior seems much too noisy, as well as inconsistent with the
! 		 * GRANT case.)
! 		 */
! 		this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! 		if (is_grant)
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("no privileges were granted")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("not all privileges were granted")));
! 		}
! 		else
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("no privileges could be revoked")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("not all privileges could be revoked")));
! 		}
  
  		/*
  		 * Generate new ACL.
--- 932,952 ----
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), istmt->privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * Restrict the privileges to what we can actually grant, and emit
! 		 * the standards-mandated warning and error messages.
  		 */
! 		this_privileges =
! 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
! 									 istmt->all_privs, istmt->privileges,
! 									 langId, grantorId,
! 									 ACL_ALL_RIGHTS_LANGUAGE,
! 									 ACL_KIND_LANGUAGE,
! 									 NameStr(pg_language_tuple->lanname));
  
  		/*
  		 * Generate new ACL.
***************
*** 1053,1061 ****
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, is_grant,
! 									   grant_option, behavior,
! 									   grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
--- 956,964 ----
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! 									   istmt->grant_option, istmt->behavior,
! 									   istmt->grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 1078,1084 ****
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
! 							  ownerId, is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
--- 981,987 ----
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(LanguageRelationId, HeapTupleGetOid(tuple),
! 							  ownerId, istmt->is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
***************
*** 1094,1112 ****
  }
  
  static void
! ExecGrant_Namespace(bool is_grant, List *objects, bool all_privs,
!  					AclMode privileges, List *grantees, bool grant_option,
!  					DropBehavior behavior)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (all_privs && privileges == ACL_NO_RIGHTS)
! 		privileges = ACL_ALL_RIGHTS_NAMESPACE;
  
  	relation = heap_open(NamespaceRelationId, RowExclusiveLock);
  
! 	foreach(cell, objects)
  	{
  		Oid			nspid = lfirst_oid(cell);
  		Form_pg_namespace pg_namespace_tuple;
--- 997,1013 ----
  }
  
  static void
! ExecGrant_Namespace(InternalGrant *istmt)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! 		istmt->privileges = ACL_ALL_RIGHTS_NAMESPACE;
  
  	relation = heap_open(NamespaceRelationId, RowExclusiveLock);
  
! 	foreach(cell, istmt->objects)
  	{
  		Oid			nspid = lfirst_oid(cell);
  		Form_pg_namespace pg_namespace_tuple;
***************
*** 1150,1205 ****
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * If we found no grant options, consider whether to issue a hard
! 		 * error.  Per spec, having any privilege at all on the object will
! 		 * get you by here.
  		 */
! 		if (avail_goptions == ACL_NO_RIGHTS)
! 		{
! 			if (pg_namespace_aclmask(HeapTupleGetOid(tuple),
! 									 grantorId,
! 									 ACL_ALL_RIGHTS_NAMESPACE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_NAMESPACE),
! 									 ACLMASK_ANY) == ACL_NO_RIGHTS)
! 				aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_NAMESPACE,
! 							   NameStr(pg_namespace_tuple->nspname));
! 		}
! 
! 		/*
! 		 * Restrict the operation to what we can actually grant or revoke, and
! 		 * issue a warning if appropriate.	(For REVOKE this isn't quite what
! 		 * the spec says to do: the spec seems to want a warning only if no
! 		 * privilege bits actually change in the ACL. In practice that
! 		 * behavior seems much too noisy, as well as inconsistent with the
! 		 * GRANT case.)
! 		 */
! 		this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! 		if (is_grant)
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("no privileges were granted")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("not all privileges were granted")));
! 		}
! 		else
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("no privileges could be revoked")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("not all privileges could be revoked")));
! 		}
  
  		/*
  		 * Generate new ACL.
--- 1051,1071 ----
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), istmt->privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * Restrict the privileges to what we can actually grant, and emit
! 		 * the standards-mandated warning and error messages.
  		 */
! 		this_privileges =
! 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
! 									 istmt->all_privs, istmt->privileges,
! 									 nspid, grantorId,
! 									 ACL_ALL_RIGHTS_NAMESPACE,
! 									 ACL_KIND_NAMESPACE,
! 									 NameStr(pg_namespace_tuple->nspname));
  
  		/*
  		 * Generate new ACL.
***************
*** 1209,1217 ****
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, is_grant,
! 									   grant_option, behavior,
! 									   grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
--- 1075,1083 ----
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! 									   istmt->grant_option, istmt->behavior,
! 									   istmt->grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 1234,1240 ****
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
! 							  ownerId, is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
--- 1100,1106 ----
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(NamespaceRelationId, HeapTupleGetOid(tuple),
! 							  ownerId, istmt->is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
***************
*** 1250,1268 ****
  }
  
  static void
! ExecGrant_Tablespace(bool is_grant, List *objects, bool all_privs,
! 					 AclMode privileges, List *grantees, bool grant_option,
! 					 DropBehavior behavior)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (all_privs && privileges == ACL_NO_RIGHTS)
! 		privileges = ACL_ALL_RIGHTS_TABLESPACE;
  
  	relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
  
! 	foreach(cell, objects)
  	{
  		Oid			tblId = lfirst_oid(cell);
  		Form_pg_tablespace pg_tablespace_tuple;
--- 1116,1132 ----
  }
  
  static void
! ExecGrant_Tablespace(InternalGrant *istmt)
  {
  	Relation	relation;
  	ListCell   *cell;
  
! 	if (istmt->all_privs && istmt->privileges == ACL_NO_RIGHTS)
! 		istmt->privileges = ACL_ALL_RIGHTS_TABLESPACE;
  
  	relation = heap_open(TableSpaceRelationId, RowExclusiveLock);
  
! 	foreach(cell, istmt->objects)
  	{
  		Oid			tblId = lfirst_oid(cell);
  		Form_pg_tablespace pg_tablespace_tuple;
***************
*** 1312,1367 ****
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * If we found no grant options, consider whether to issue a hard
! 		 * error.  Per spec, having any privilege at all on the object will
! 		 * get you by here.
! 		 */
! 		if (avail_goptions == ACL_NO_RIGHTS)
! 		{
! 			if (pg_tablespace_aclmask(HeapTupleGetOid(tuple),
! 									  grantorId,
! 									  ACL_ALL_RIGHTS_TABLESPACE | ACL_GRANT_OPTION_FOR(ACL_ALL_RIGHTS_TABLESPACE),
! 									  ACLMASK_ANY) == ACL_NO_RIGHTS)
! 				aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_TABLESPACE,
! 							   NameStr(pg_tablespace_tuple->spcname));
! 		}
! 
! 		/*
! 		 * Restrict the operation to what we can actually grant or revoke, and
! 		 * issue a warning if appropriate.	(For REVOKE this isn't quite what
! 		 * the spec says to do: the spec seems to want a warning only if no
! 		 * privilege bits actually change in the ACL. In practice that
! 		 * behavior seems much too noisy, as well as inconsistent with the
! 		 * GRANT case.)
  		 */
! 		this_privileges = privileges & ACL_OPTION_TO_PRIVS(avail_goptions);
! 		if (is_grant)
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("no privileges were granted")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_GRANTED),
! 						 errmsg("not all privileges were granted")));
! 		}
! 		else
! 		{
! 			if (this_privileges == 0)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("no privileges could be revoked")));
! 			else if (!all_privs && this_privileges != privileges)
! 				ereport(WARNING,
! 						(errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
! 						 errmsg("not all privileges could be revoked")));
! 		}
  
  		/*
  		 * Generate new ACL.
--- 1176,1196 ----
  			old_acl = DatumGetAclPCopy(aclDatum);
  
  		/* Determine ID to do the grant as, and available grant options */
! 		select_best_grantor(GetUserId(), istmt->privileges,
  							old_acl, ownerId,
  							&grantorId, &avail_goptions);
  
  		/*
! 		 * Restrict the privileges to what we can actually grant, and emit
! 		 * the standards-mandated warning and error messages.
  		 */
! 		this_privileges =
! 			restrict_and_check_grant(istmt->is_grant, avail_goptions,
! 									 istmt->all_privs, istmt->privileges,
! 									 tblId, grantorId,
! 									 ACL_ALL_RIGHTS_TABLESPACE,
! 									 ACL_KIND_TABLESPACE,
! 									 NameStr(pg_tablespace_tuple->spcname));
  
  		/*
  		 * Generate new ACL.
***************
*** 1371,1379 ****
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, is_grant,
! 									   grant_option, behavior,
! 									   grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
--- 1200,1208 ----
  		 */
  		noldmembers = aclmembers(old_acl, &oldmembers);
  
! 		new_acl = merge_acl_with_grant(old_acl, istmt->is_grant,
! 									   istmt->grant_option, istmt->behavior,
! 									   istmt->grantees, this_privileges,
  									   grantorId, ownerId);
  
  		nnewmembers = aclmembers(new_acl, &newmembers);
***************
*** 1396,1402 ****
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(TableSpaceRelationId, tblId,
! 							  ownerId, is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
--- 1225,1231 ----
  
  		/* Update the shared dependency ACL info */
  		updateAclDependencies(TableSpaceRelationId, tblId,
! 							  ownerId, istmt->is_grant,
  							  noldmembers, oldmembers,
  							  nnewmembers, newmembers);
  
Index: src/backend/catalog/pg_shdepend.c
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/backend/catalog/pg_shdepend.c,v
retrieving revision 1.4
diff -c -r1.4 pg_shdepend.c
*** src/backend/catalog/pg_shdepend.c	21 Nov 2005 12:49:30 -0000	1.4
--- src/backend/catalog/pg_shdepend.c	21 Nov 2005 15:08:16 -0000
***************
*** 1122,1127 ****
--- 1122,1128 ----
  			{
  				ObjectAddress	obj;
  				GrantObjectType	objtype;
+ 				InternalGrant	istmt;
  
  				/* Shouldn't happen */
  				case SHARED_DEPENDENCY_PIN:
***************
*** 1132,1153 ****
  					switch (sdepForm->classid)
  					{
  						case RelationRelationId:
! 							objtype = ACL_OBJECT_RELATION;
  							break;
  						case DatabaseRelationId:
! 							objtype = ACL_OBJECT_DATABASE;
  							break;
  						case ProcedureRelationId:
! 							objtype = ACL_OBJECT_FUNCTION;
  							break;
  						case LanguageRelationId:
! 							objtype = ACL_OBJECT_LANGUAGE;
  							break;
  						case NamespaceRelationId:
! 							objtype = ACL_OBJECT_NAMESPACE;
  							break;
  						case TableSpaceRelationId:
! 							objtype = ACL_OBJECT_TABLESPACE;
  							break;
  						default:
  							elog(ERROR, "unexpected object type %d",
--- 1133,1154 ----
  					switch (sdepForm->classid)
  					{
  						case RelationRelationId:
! 							istmt.objtype = ACL_OBJECT_RELATION;
  							break;
  						case DatabaseRelationId:
! 							istmt.objtype = ACL_OBJECT_DATABASE;
  							break;
  						case ProcedureRelationId:
! 							istmt.objtype = ACL_OBJECT_FUNCTION;
  							break;
  						case LanguageRelationId:
! 							istmt.objtype = ACL_OBJECT_LANGUAGE;
  							break;
  						case NamespaceRelationId:
! 							istmt.objtype = ACL_OBJECT_NAMESPACE;
  							break;
  						case TableSpaceRelationId:
! 							istmt.objtype = ACL_OBJECT_TABLESPACE;
  							break;
  						default:
  							elog(ERROR, "unexpected object type %d",
***************
*** 1156,1166 ****
  							objtype = (GrantObjectType) 0;
  							break;
  					}
  
! 					ExecGrantStmt_oids(false, objtype,
! 									   list_make1_oid(sdepForm->objid), true,
! 									   ACL_NO_RIGHTS, list_make1_oid(roleid),
! 									   false, DROP_CASCADE);
  					break;
  				case SHARED_DEPENDENCY_OWNER:
  					/*
--- 1157,1171 ----
  							objtype = (GrantObjectType) 0;
  							break;
  					}
+ 					istmt.is_grant = false;
+ 					istmt.objects = list_make1_oid(sdepForm->objid);
+ 					istmt.all_privs = true;
+ 					istmt.privileges = ACL_NO_RIGHTS;
+ 					istmt.grantees = list_make1_oid(roleid);
+ 					istmt.grant_option = false;
+ 					istmt.behavior = DROP_CASCADE;
  
! 					ExecGrantStmt_oids(&istmt);
  					break;
  				case SHARED_DEPENDENCY_OWNER:
  					/*
Index: src/include/utils/acl.h
===================================================================
RCS file: /home/alvherre/cvs/pgsql/src/include/utils/acl.h,v
retrieving revision 1.89
diff -c -r1.89 acl.h
*** src/include/utils/acl.h	21 Nov 2005 12:49:33 -0000	1.89
--- src/include/utils/acl.h	21 Nov 2005 14:32:59 -0000
***************
*** 182,187 ****
--- 182,207 ----
  } AclObjectKind;
  
  /*
+  * The information about one Grant/Revoke statement, in internal format: object
+  * and grantees names have been turned into Oids, the privilege list is an
+  * AclMode bitmask.  If 'privileges' is ACL_NO_RIGHTS (the 0 value) and
+  * all_privs is true, it will be internally turned into the right kind of
+  * ACL_ALL_RIGHTS_*, depending on the object type (NB - this will modify the
+  * InternalGrant struct!)
+  */
+ typedef struct
+ {
+ 	bool    is_grant;
+ 	GrantObjectType objtype;
+ 	List   *objects;
+ 	bool    all_privs;
+ 	AclMode privileges;
+ 	List   *grantees;
+ 	bool    grant_option;
+ 	DropBehavior behavior;
+ } InternalGrant;
+ 
+ /*
   * routines used internally
   */
  extern Acl *acldefault(GrantObjectType objtype, Oid ownerId);
***************
*** 221,229 ****
   * prototypes for functions in aclchk.c
   */
  extern void ExecuteGrantStmt(GrantStmt *stmt);
! extern void ExecGrantStmt_oids(bool is_grant, GrantObjectType objtype,
! 				   List *objects, bool all_privs, AclMode privileges,
! 				   List *grantees, bool grant_option, DropBehavior behavior);
  
  extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid,
  				 AclMode mask, AclMaskHow how);
--- 241,247 ----
   * prototypes for functions in aclchk.c
   */
  extern void ExecuteGrantStmt(GrantStmt *stmt);
! extern void ExecGrantStmt_oids(InternalGrant *istmt);
  
  extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid,
  				 AclMode mask, AclMaskHow how);


view thread (12+ messages)  latest in thread

reply

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Reply to all the recipients using the --to and --cc options:
  reply via email

  To: [email protected]
  Cc: [email protected], [email protected], [email protected]
  Subject: Re: aclchk.c refactor
  In-Reply-To: <[email protected]>

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

This inbox is served by agora; see mirroring instructions
for how to clone and mirror all data and code used for this inbox