diff --git a/src/backend/commands/aggregatecmds.c b/src/backend/commands/aggregatecmds.c
index 6335757981ec32eb50cee43498cab6e56393ebf1..e96f328d190a70c1e06fdae809667899cb6d747c 100644
--- a/src/backend/commands/aggregatecmds.c
+++ b/src/backend/commands/aggregatecmds.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.27 2005/06/28 05:08:53 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/aggregatecmds.c,v 1.28 2005/07/14 21:46:29 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -302,6 +302,7 @@ AlterAggregateOwner(List *name, TypeName *basetype, Oid newOwnerId)
 	HeapTuple	tup;
 	Form_pg_proc procForm;
 	Relation	rel;
+	AclResult	aclresult;
 
 	/*
 	 * if a basetype is passed in, then attempt to find an aggregate for
@@ -331,11 +332,20 @@ AlterAggregateOwner(List *name, TypeName *basetype, Oid newOwnerId)
 	 */
 	if (procForm->proowner != newOwnerId)
 	{
-		/* Otherwise, must be superuser to change object ownership */
-		if (!superuser())
-			ereport(ERROR,
-					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-					 errmsg("must be superuser to change owner")));
+		/* Otherwise, must be owner of the existing object */
+		if (!pg_proc_ownercheck(procOid, GetUserId()))
+			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
+						   NameListToString(name));
+
+		/* Must be able to become new owner */
+		check_is_member_of_role(GetUserId(), newOwnerId);
+
+		/* New owner must have CREATE privilege on namespace */
+		aclresult = pg_namespace_aclcheck(procForm->pronamespace, newOwnerId,
+										  ACL_CREATE);
+		if (aclresult != ACLCHECK_OK)
+			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+						   get_namespace_name(procForm->pronamespace));
 
 		/*
 		 * Modify the owner --- okay to scribble on tup because it's a
diff --git a/src/backend/commands/conversioncmds.c b/src/backend/commands/conversioncmds.c
index 9cc72ec7327a0fa30f4bf26b3c696b622c1f01ed..81e889aa4ee1d592cc2fbb0366bb30eca139c670 100644
--- a/src/backend/commands/conversioncmds.c
+++ b/src/backend/commands/conversioncmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/conversioncmds.c,v 1.20 2005/07/07 20:39:58 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/conversioncmds.c,v 1.21 2005/07/14 21:46:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -152,8 +152,7 @@ RenameConversion(List *name, const char *newname)
 					 newname, get_namespace_name(namespaceOid))));
 
 	/* must be owner */
-	if (!superuser() &&
-		((Form_pg_conversion) GETSTRUCT(tup))->conowner != GetUserId())
+	if (!pg_conversion_ownercheck(conversionOid,GetUserId()))
 		aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
 					   NameListToString(name));
 
@@ -182,6 +181,7 @@ AlterConversionOwner(List *name, Oid newOwnerId)
 	HeapTuple	tup;
 	Relation	rel;
 	Form_pg_conversion convForm;
+	AclResult	aclresult;
 
 	rel = heap_open(ConversionRelationId, RowExclusiveLock);
 
@@ -206,11 +206,20 @@ AlterConversionOwner(List *name, Oid newOwnerId)
 	 */
 	if (convForm->conowner != newOwnerId)
 	{
-		/* Otherwise, must be superuser to change object ownership */
-		if (!superuser())
-			ereport(ERROR,
-					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-					 errmsg("must be superuser to change owner")));
+		/* Otherwise, must be owner of the existing object */
+		if (!pg_conversion_ownercheck(HeapTupleGetOid(tup),GetUserId()))
+			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CONVERSION,
+						   NameListToString(name));
+
+		/* Must be able to become new owner */
+		check_is_member_of_role(GetUserId(), newOwnerId);
+
+		/* New owner must have CREATE privilege on namespace */
+		aclresult = pg_namespace_aclcheck(convForm->connamespace, newOwnerId,
+										  ACL_CREATE);
+		if (aclresult != ACLCHECK_OK)
+			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+						   get_namespace_name(convForm->connamespace));
 
 		/*
 		 * Modify the owner --- okay to scribble on tup because it's a
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
index 7f6791abfd346af4ef975e2ea7519e72ac6f22ac..4e23def836161fa2bac4573db9052e9c19b9b1ad 100644
--- a/src/backend/commands/dbcommands.c
+++ b/src/backend/commands/dbcommands.c
@@ -15,7 +15,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.166 2005/07/08 04:12:24 neilc Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/dbcommands.c,v 1.167 2005/07/14 21:46:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -193,23 +193,19 @@ createdb(const CreatedbStmt *stmt)
 	else
 		datdba = GetUserId();
 
-	if (is_member_of_role(GetUserId(), datdba))
-	{
-		/* creating database for self: createdb is required */
-		if (!have_createdb_privilege())
-			ereport(ERROR,
-					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-					 errmsg("permission denied to create database")));
-	}
-	else
-	{
-		/* creating database for someone else: must be superuser */
-		/* note that the someone else need not have any permissions */
-		if (!superuser())
-			ereport(ERROR,
-					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-					 errmsg("must be superuser to create database for another user")));
-	}
+	/*
+	 * To create a database, must have createdb privilege and must be able
+	 * to become the target role (this does not imply that the target role
+	 * itself must have createdb privilege).  The latter provision guards
+	 * against "giveaway" attacks.  Note that a superuser will always have
+	 * both of these privileges a fortiori.
+	 */
+	if (!have_createdb_privilege())
+		ereport(ERROR,
+				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+				 errmsg("permission denied to create database")));
+
+	check_is_member_of_role(GetUserId(), datdba);
 
 	/*
 	 * Check for db name conflict.	There is a race condition here, since
@@ -930,11 +926,26 @@ AlterDatabaseOwner(const char *dbname, Oid newOwnerId)
 		bool		isNull;
 		HeapTuple	newtuple;
 
-		/* must be superuser to change ownership */
-		if (!superuser())
+		/* Otherwise, must be owner of the existing object */
+		if (!pg_database_ownercheck(HeapTupleGetOid(tuple),GetUserId()))
+			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_DATABASE,
+						   dbname);
+
+		/* Must be able to become new owner */
+		check_is_member_of_role(GetUserId(), newOwnerId);
+
+		/*
+		 * must have createdb rights 
+		 *
+		 * NOTE: This is different from other alter-owner checks in 
+		 * that the current user is checked for createdb privileges 
+		 * instead of the destination owner.  This is consistent
+		 * with the CREATE case for databases.
+		 */
+		if (!have_createdb_privilege())
 			ereport(ERROR,
 					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-					 errmsg("must be superuser to change owner")));
+					 errmsg("permission denied to change owner of database")));
 
 		memset(repl_null, ' ', sizeof(repl_null));
 		memset(repl_repl, ' ', sizeof(repl_repl));
diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c
index 8867538f8eb2c04290094a4c8ba74801b3808dbe..7e205890c90251cedfec2f009bd6e22c7a3c5a82 100644
--- a/src/backend/commands/functioncmds.c
+++ b/src/backend/commands/functioncmds.c
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.63 2005/07/07 20:39:58 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/functioncmds.c,v 1.64 2005/07/14 21:46:29 tgl Exp $
  *
  * DESCRIPTION
  *	  These routines take the parse tree and pick out the
@@ -859,6 +859,7 @@ AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId)
 	HeapTuple	tup;
 	Form_pg_proc procForm;
 	Relation	rel;
+	AclResult	aclresult;
 
 	rel = heap_open(ProcedureRelationId, RowExclusiveLock);
 
@@ -892,11 +893,20 @@ AlterFunctionOwner(List *name, List *argtypes, Oid newOwnerId)
 		bool		isNull;
 		HeapTuple	newtuple;
 
-		/* Otherwise, must be superuser to change object ownership */
-		if (!superuser())
-			ereport(ERROR,
-					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-					 errmsg("must be superuser to change owner")));
+		/* Otherwise, must be owner of the existing object */
+		if (!pg_proc_ownercheck(procOid,GetUserId()))
+			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_PROC,
+						   NameListToString(name));
+
+		/* Must be able to become new owner */
+		check_is_member_of_role(GetUserId(), newOwnerId);
+
+		/* New owner must have CREATE privilege on namespace */
+		aclresult = pg_namespace_aclcheck(procForm->pronamespace, newOwnerId,
+										  ACL_CREATE);
+		if (aclresult != ACLCHECK_OK)
+			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+					get_namespace_name(procForm->pronamespace));
 
 		memset(repl_null, ' ', sizeof(repl_null));
 		memset(repl_repl, ' ', sizeof(repl_repl));
diff --git a/src/backend/commands/opclasscmds.c b/src/backend/commands/opclasscmds.c
index a0d0abd553d03c700a1dace74c574791200df8d6..c9d11da70eb92405f10f6f1525901d026e4607bf 100644
--- a/src/backend/commands/opclasscmds.c
+++ b/src/backend/commands/opclasscmds.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.34 2005/07/07 20:39:58 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/opclasscmds.c,v 1.35 2005/07/14 21:46:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -892,6 +892,7 @@ AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId)
 	char	   *opcname;
 	HeapTuple	tup;
 	Relation	rel;
+	AclResult	aclresult;
 	Form_pg_opclass opcForm;
 
 	amOid = GetSysCacheOid(AMNAME,
@@ -950,11 +951,20 @@ AlterOpClassOwner(List *name, const char *access_method, Oid newOwnerId)
 	 */
 	if (opcForm->opcowner != newOwnerId)
 	{
-		/* Otherwise, must be superuser to change object ownership */
-		if (!superuser())
-			ereport(ERROR,
-					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-					 errmsg("must be superuser to change owner")));
+		/* Otherwise, must be owner of the existing object */
+		if (!pg_opclass_ownercheck(HeapTupleGetOid(tup),GetUserId()))
+			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPCLASS,
+						   NameListToString(name));
+
+		/* Must be able to become new owner */
+		check_is_member_of_role(GetUserId(), newOwnerId);
+
+		/* New owner must have CREATE privilege on namespace */
+		aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
+										  ACL_CREATE);
+		if (aclresult != ACLCHECK_OK)
+			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+					get_namespace_name(namespaceOid));
 
 		/*
 		 * Modify the owner --- okay to scribble on tup because it's a
diff --git a/src/backend/commands/operatorcmds.c b/src/backend/commands/operatorcmds.c
index ae93e9230eed54b29ebe572865c006adcfb43af4..d36ac6acd0bc0b5ed0709c22c34040d7da1bd341 100644
--- a/src/backend/commands/operatorcmds.c
+++ b/src/backend/commands/operatorcmds.c
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.23 2005/07/07 20:39:58 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/operatorcmds.c,v 1.24 2005/07/14 21:46:29 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -274,6 +274,7 @@ AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2,
 	Oid			operOid;
 	HeapTuple	tup;
 	Relation	rel;
+	AclResult	aclresult;
 	Form_pg_operator oprForm;
 
 	rel = heap_open(OperatorRelationId, RowExclusiveLock);
@@ -295,11 +296,20 @@ AlterOperatorOwner(List *name, TypeName *typeName1, TypeName *typeName2,
 	 */
 	if (oprForm->oprowner != newOwnerId)
 	{
-		/* Otherwise, must be superuser to change object ownership */
-		if (!superuser())
-			ereport(ERROR,
-					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-					 errmsg("must be superuser to change owner")));
+		/* Otherwise, must be owner of the existing object */
+		if (!pg_oper_ownercheck(operOid,GetUserId()))
+			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_OPER,
+						   NameListToString(name));
+
+		/* Must be able to become new owner */
+		check_is_member_of_role(GetUserId(), newOwnerId);
+
+		/* New owner must have CREATE privilege on namespace */
+		aclresult = pg_namespace_aclcheck(oprForm->oprnamespace, newOwnerId,
+										  ACL_CREATE);
+		if (aclresult != ACLCHECK_OK)
+			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+					get_namespace_name(oprForm->oprnamespace));
 
 		/*
 		 * Modify the owner --- okay to scribble on tup because it's a
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index c4c20ddeb39ecba592d7845d1129c44200376a9d..65a6edeabc79a1fc6198987b663f299e702f0921 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.32 2005/07/07 20:39:58 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/schemacmds.c,v 1.33 2005/07/14 21:46:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -49,54 +49,45 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
 	saved_uid = GetUserId();
 
 	/*
-	 * Figure out user identities.
+	 * Who is supposed to own the new schema?
 	 */
-
-	if (!authId)
-	{
-		owner_uid = saved_uid;
-	}
-	else if (superuser())
-	{
+	if (authId)
 		owner_uid = get_roleid_checked(authId);
-
-		/*
-		 * Set the current user to the requested authorization so that
-		 * objects created in the statement have the requested owner.
-		 * (This will revert to session user on error or at the end of
-		 * this routine.)
-		 */
-		SetUserId(owner_uid);
-	}
 	else
-	{
-		const char *owner_name;
-
-		/* not superuser */
 		owner_uid = saved_uid;
-		owner_name = GetUserNameFromId(owner_uid);
-		if (strcmp(authId, owner_name) != 0)
-			ereport(ERROR,
-					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-					 errmsg("permission denied"),
-					 errdetail("\"%s\" is not a superuser, so cannot create a schema for \"%s\"",
-							   owner_name, authId)));
-	}
 
 	/*
-	 * Permissions checks.
+	 * To create a schema, must have schema-create privilege on the current
+	 * database and must be able to become the target role (this does not
+	 * imply that the target role itself must have create-schema privilege).
+	 * The latter provision guards against "giveaway" attacks.  Note that
+	 * a superuser will always have both of these privileges a fortiori.
 	 */
 	aclresult = pg_database_aclcheck(MyDatabaseId, saved_uid, ACL_CREATE);
 	if (aclresult != ACLCHECK_OK)
 		aclcheck_error(aclresult, ACL_KIND_DATABASE,
 					   get_database_name(MyDatabaseId));
 
+	check_is_member_of_role(saved_uid, owner_uid);
+
+	/* Additional check to protect reserved schema names */
 	if (!allowSystemTableMods && IsReservedName(schemaName))
 		ereport(ERROR,
 				(errcode(ERRCODE_RESERVED_NAME),
 				 errmsg("unacceptable schema name \"%s\"", schemaName),
 		errdetail("The prefix \"pg_\" is reserved for system schemas.")));
 
+	/*
+	 * If the requested authorization is different from the current user,
+	 * temporarily set the current user so that the object(s) will be
+	 * created with the correct ownership.
+	 *
+	 * (The setting will revert to session user on error or at the end of
+	 * this routine.)
+	 */
+	if (saved_uid != owner_uid)
+		SetUserId(owner_uid);
+
 	/* Create the schema's namespace */
 	namespaceId = NamespaceCreate(schemaName, owner_uid);
 
@@ -308,12 +299,29 @@ AlterSchemaOwner(const char *name, Oid newOwnerId)
 		Datum		aclDatum;
 		bool		isNull;
 		HeapTuple	newtuple;
+		AclResult	aclresult;
+
+		/* Otherwise, must be owner of the existing object */
+		if (!pg_namespace_ownercheck(HeapTupleGetOid(tup),GetUserId()))
+			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_NAMESPACE,
+						   name);
+
+		/* Must be able to become new owner */
+		check_is_member_of_role(GetUserId(),newOwnerId);
 
-		/* Otherwise, must be superuser to change object ownership */
-		if (!superuser())
-			ereport(ERROR,
-					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-					 errmsg("must be superuser to change owner")));
+		/*
+		 * must have create-schema rights
+		 *
+		 * NOTE: This is different from other alter-owner checks in 
+		 * that the current user is checked for create privileges 
+		 * instead of the destination owner.  This is consistent
+		 * with the CREATE case for schemas.
+		 */
+		aclresult = pg_database_aclcheck(MyDatabaseId, GetUserId(),
+										 ACL_CREATE);
+		if (aclresult != ACLCHECK_OK)
+			aclcheck_error(aclresult, ACL_KIND_DATABASE,
+						   get_database_name(MyDatabaseId));
 
 		memset(repl_null, ' ', sizeof(repl_null));
 		memset(repl_repl, ' ', sizeof(repl_repl));
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 2b50a402fc882cae383e69b0eda96ed18929b8a6..c06c272cbdd1bb3e0d469043994f59d42a4a2f39 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.163 2005/07/07 20:39:58 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/tablecmds.c,v 1.164 2005/07/14 21:46:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -5286,12 +5286,23 @@ ATExecChangeOwner(Oid relationOid, Oid newOwnerId)
 		Datum		aclDatum;
 		bool		isNull;
 		HeapTuple	newtuple;
+		Oid		    namespaceOid = tuple_class->relnamespace;
+		AclResult	aclresult;
 
-		/* Otherwise, check that we are the superuser */
-		if (!superuser())
-			ereport(ERROR,
-					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-					 errmsg("must be superuser to change owner")));
+		/* Otherwise, must be owner of the existing object */
+		if (!pg_class_ownercheck(relationOid,GetUserId()))
+			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_CLASS,
+						   RelationGetRelationName(target_rel));
+
+		/* Must be able to become new owner */
+		check_is_member_of_role(GetUserId(), newOwnerId);
+
+		/* New owner must have CREATE privilege on namespace */
+		aclresult = pg_namespace_aclcheck(namespaceOid, newOwnerId,
+										  ACL_CREATE);
+		if (aclresult != ACLCHECK_OK)
+			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+						   get_namespace_name(namespaceOid));
 
 		memset(repl_null, ' ', sizeof(repl_null));
 		memset(repl_repl, ' ', sizeof(repl_repl));
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index a2cce14335c0c6ffe87c1c6346a115f5d3ed8b41..06c939c2d5c79b5b34e2df66099cd8f3c61024fa 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -37,7 +37,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.25 2005/07/07 20:39:58 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/tablespace.c,v 1.26 2005/07/14 21:46:29 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -788,11 +788,23 @@ AlterTableSpaceOwner(const char *name, Oid newOwnerId)
 		bool		isNull;
 		HeapTuple	newtuple;
 
-		/* Otherwise, must be superuser to change object ownership */
-		if (!superuser())
-			ereport(ERROR,
-					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-					 errmsg("must be superuser to change owner")));
+		/* Otherwise, must be owner of the existing object */
+		if (!pg_tablespace_ownercheck(HeapTupleGetOid(tup), GetUserId()))
+			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TABLESPACE,
+						   name);
+
+		/* Must be able to become new owner */
+		check_is_member_of_role(GetUserId(), newOwnerId);
+
+		/*
+		 * Normally we would also check for create permissions here,
+		 * but there are none for tablespaces so we follow what rename
+		 * tablespace does and omit the create permissions check.
+		 *
+		 * NOTE: Only superusers may create tablespaces to begin with and
+		 * so initially only a superuser would be able to change its
+		 * ownership anyway.
+		 */
 
 		memset(repl_null, ' ', sizeof(repl_null));
 		memset(repl_repl, ' ', sizeof(repl_repl));
diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c
index 7406e15376abd7d76b4ff8e3e37df93d974a4d4e..0979e8aeec247700ed659854ed343441ae1505f4 100644
--- a/src/backend/commands/typecmds.c
+++ b/src/backend/commands/typecmds.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.75 2005/07/10 21:13:58 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.76 2005/07/14 21:46:29 tgl Exp $
  *
  * DESCRIPTION
  *	  The "DefineFoo" routines take the parse tree and pick out the
@@ -2025,6 +2025,7 @@ AlterTypeOwner(List *names, Oid newOwnerId)
 	Relation	rel;
 	HeapTuple	tup;
 	Form_pg_type typTup;
+	AclResult	aclresult;
 
 	/* Make a TypeName so we can use standard type lookup machinery */
 	typename = makeNode(TypeName);
@@ -2067,11 +2068,20 @@ AlterTypeOwner(List *names, Oid newOwnerId)
 	 */
 	if (typTup->typowner != newOwnerId)
 	{
-		/* Otherwise, must be superuser to change object ownership */
-		if (!superuser())
-			ereport(ERROR,
-					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
-					 errmsg("must be superuser to change owner")));
+		/* Otherwise, must be owner of the existing object */
+		if (!pg_type_ownercheck(HeapTupleGetOid(tup),GetUserId()))
+			aclcheck_error(ACLCHECK_NOT_OWNER, ACL_KIND_TYPE,
+						   TypeNameToString(typename));
+
+		/* Must be able to become new owner */
+		check_is_member_of_role(GetUserId(), newOwnerId);
+
+		/* New owner must have CREATE privilege on namespace */
+		aclresult = pg_namespace_aclcheck(typTup->typnamespace, newOwnerId,
+										  ACL_CREATE);
+		if (aclresult != ACLCHECK_OK)
+			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,
+						   get_namespace_name(typTup->typnamespace));
 
 		/*
 		 * Modify the owner --- okay to scribble on typTup because it's a
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index a416def815593f562738a49af6a19d6bbf917c7a..3fedb33a8a51fbdfa19d1e5ba0c8607ad5f9ac46 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *	  $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.118 2005/07/07 20:39:58 tgl Exp $
+ *	  $PostgreSQL: pgsql/src/backend/utils/adt/acl.c,v 1.119 2005/07/14 21:46:30 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2541,6 +2541,10 @@ is_member_of_role(Oid member, Oid role)
 	if (member == role)
 		return true;
 
+	/* Superusers have every privilege, so are part of every role */
+	if (superuser_arg(member))
+		return true;
+
 	/* If cache is already valid, just use the list */
 	if (OidIsValid(cached_role) && cached_role == member)
 		return list_member_oid(cached_memberships, role);
@@ -2604,6 +2608,20 @@ is_member_of_role(Oid member, Oid role)
 	return list_member_oid(cached_memberships, role);
 }
 
+/*
+ * check_is_member_of_role
+ *		is_member_of_role with a standard permission-violation error if not
+ */
+void
+check_is_member_of_role(Oid member, Oid role)
+{
+	if (!is_member_of_role(member, role))
+		ereport(ERROR,
+				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+				 errmsg("must be member of role \"%s\"",
+						GetUserNameFromId(role))));
+}
+
 
 /*
  * Is member an admin of role (directly or indirectly)?  That is, is it
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index 7defb4e1e2870feafdb2563c47989ea8717c9199..d3ef0031985aa427fb111992e1016d81f5b28d17 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.81 2005/07/07 20:40:00 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/utils/acl.h,v 1.82 2005/07/14 21:46:30 tgl Exp $
  *
  * NOTES
  *	  An ACL array is simply an array of AclItems, representing the union
@@ -212,6 +212,7 @@ extern int aclmembers(const Acl *acl, Oid **roleids);
 
 extern bool is_member_of_role(Oid member, Oid role);
 extern bool is_admin_of_role(Oid member, Oid role);
+extern void check_is_member_of_role(Oid member, Oid role);
 
 extern void initialize_acl(void);