Hi, this is revised version.

> Kyotaro HORIGUCHI wrote:
> 
> > - Storage for new information
> > 
> > The new struct NameId stores an identifier which telling what it
> > logically is using the new enum NameIdTypes.
> 
> I think NameId is a bad name for this.  My point is that NameId, as it
> stands, might be a name for anything, not just a role; and the object it
> identifies is not an Id either.  Maybe RoleSpec?

Yeah! I felt it no good even if it were a generic type for
various "Name of something or its oid". RoleSpec sounds much better.

> Do we need a public_ok
> argument to get_nameid_oid() (get a better name for this function too)

Maybe get_rolespec_oid() as a name ofter its parameter type?

> so that callers don't have to check for InvalidOid argument?  I think
> the arrangement you propose is not very convenient; it'd be best to
> avoid duplicating the check for InvalidOid in all callers of the new
> function, particularly where there was no check before.

I agree that It'd be better keeping away from duplicated
InvalidOid checks, but public_ok seems a bit myopic. Since
there's no reasonable border between functions accepting 'public'
and others, such kind of solution would not be reasonable..

What about checking it being a PUBLIC or not *before* calling
get_rolespec_oid()?

The attached patch modified in the following points.

 - rename NameId to RoleSpec and NameIdType to RoleSpecTypes.
 - rename get_nameid_oid() to get_rolespec_oid().
 - rename roleNamesToIds() to roleSpecsToIds().
 - some struct members are changed such as authname to authrole.
 - check if rolespec is "public" or not before calling get_rolespec_oid()
 - ExecAlterDefaultPrivilegesStmt and ExecuteGrantStmt does
   slightly different things about ACL_ID_PUBLIC but I unified it
   to the latter.
 - rebased to the current master

regards,

-- 
Kyotaro Horiguchi
NTT Open Source Software Center

CreateStmt->authrole = NULL => ?
>From 307249654c97b6449261febbfd84190fbad9111d Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyot...@lab.ntt.co.jp>
Date: Fri, 14 Nov 2014 17:37:22 +0900
Subject: [PATCH] ALTER USER CURRENT_USER v3

---
 src/backend/catalog/aclchk.c       |  30 +++---
 src/backend/commands/alter.c       |   2 +-
 src/backend/commands/extension.c   |   2 +-
 src/backend/commands/foreigncmds.c |  57 +++++------
 src/backend/commands/schemacmds.c  |  30 +++++-
 src/backend/commands/tablecmds.c   |   4 +-
 src/backend/commands/tablespace.c  |   2 +-
 src/backend/commands/user.c        |  86 +++++++++--------
 src/backend/nodes/copyfuncs.c      |  37 +++++---
 src/backend/nodes/equalfuncs.c     |  35 ++++---
 src/backend/parser/gram.y          | 190 +++++++++++++++++++++++++++----------
 src/backend/parser/parse_utilcmd.c |   4 +-
 src/backend/utils/adt/acl.c        |  34 +++++++
 src/include/commands/user.h        |   2 +-
 src/include/nodes/nodes.h          |   1 +
 src/include/nodes/parsenodes.h     |  48 +++++++---
 src/include/utils/acl.h            |   2 +-
 17 files changed, 385 insertions(+), 181 deletions(-)

diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
index d30612c..24811c6 100644
--- a/src/backend/catalog/aclchk.c
+++ b/src/backend/catalog/aclchk.c
@@ -430,13 +430,16 @@ ExecuteGrantStmt(GrantStmt *stmt)
 	foreach(cell, stmt->grantees)
 	{
 		PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
+		Oid grantee_uid = ACL_ID_PUBLIC;
 
-		if (grantee->rolname == NULL)
-			istmt.grantees = lappend_oid(istmt.grantees, ACL_ID_PUBLIC);
-		else
-			istmt.grantees =
-				lappend_oid(istmt.grantees,
-							get_role_oid(grantee->rolname, false));
+		/* "public" is mapped to ACL_ID_PUBLIC */
+		if (grantee->role->roltype != ROLESPEC_PUBLIC)
+		{
+			grantee_uid = get_rolespec_oid(grantee->role, false);
+			if (!OidIsValid(grantee_uid))
+				grantee_uid = ACL_ID_PUBLIC;
+		}
+		istmt.grantees = lappend_oid(istmt.grantees, grantee_uid);
 	}
 
 	/*
@@ -913,13 +916,16 @@ ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt)
 	foreach(cell, action->grantees)
 	{
 		PrivGrantee *grantee = (PrivGrantee *) lfirst(cell);
+		Oid grantee_uid = ACL_ID_PUBLIC;
 
-		if (grantee->rolname == NULL)
-			iacls.grantees = lappend_oid(iacls.grantees, ACL_ID_PUBLIC);
-		else
-			iacls.grantees =
-				lappend_oid(iacls.grantees,
-							get_role_oid(grantee->rolname, false));
+		/* "public" is mapped to ACL_ID_PUBLIC */
+		if (grantee->role->roltype != ROLESPEC_PUBLIC)
+		{
+			grantee_uid = get_rolespec_oid(grantee->role, false);
+			if (!OidIsValid(grantee_uid))
+				grantee_uid = ACL_ID_PUBLIC;
+		}
+		iacls.grantees = lappend_oid(iacls.grantees, grantee_uid);
 	}
 
 	/*
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
index c9a9baf..c53d4e5 100644
--- a/src/backend/commands/alter.c
+++ b/src/backend/commands/alter.c
@@ -678,7 +678,7 @@ AlterObjectNamespace_internal(Relation rel, Oid objid, Oid nspOid)
 Oid
 ExecAlterOwnerStmt(AlterOwnerStmt *stmt)
 {
-	Oid			newowner = get_role_oid(stmt->newowner, false);
+	Oid	newowner = get_rolespec_oid(stmt->newowner, false);
 
 	switch (stmt->objectType)
 	{
diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c
index 9a0afa4..52d4190 100644
--- a/src/backend/commands/extension.c
+++ b/src/backend/commands/extension.c
@@ -1370,7 +1370,7 @@ CreateExtension(CreateExtensionStmt *stmt)
 			CreateSchemaStmt *csstmt = makeNode(CreateSchemaStmt);
 
 			csstmt->schemaname = schemaName;
-			csstmt->authid = NULL;		/* will be created by current user */
+			csstmt->authrole = NULL;	/* will be created by current user */
 			csstmt->schemaElts = NIL;
 			csstmt->if_not_exists = false;
 			CreateSchemaCommand(csstmt, NULL);
diff --git a/src/backend/commands/foreigncmds.c b/src/backend/commands/foreigncmds.c
index ab4ed6c..d4c4442 100644
--- a/src/backend/commands/foreigncmds.c
+++ b/src/backend/commands/foreigncmds.c
@@ -198,24 +198,6 @@ transformGenericOptions(Oid catalogId,
 
 
 /*
- * Convert the user mapping user name to OID
- */
-static Oid
-GetUserOidFromMapping(const char *username, bool missing_ok)
-{
-	if (!username)
-		/* PUBLIC user mapping */
-		return InvalidOid;
-
-	if (strcmp(username, "current_user") == 0)
-		/* map to the owner */
-		return GetUserId();
-
-	/* map to provided user */
-	return get_role_oid(username, missing_ok);
-}
-
-/*
  * Internal workhorse for changing a data wrapper's owner.
  *
  * Allow this only for superusers; also the new owner must be a
@@ -1090,7 +1072,7 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
 	Datum		values[Natts_pg_user_mapping];
 	bool		nulls[Natts_pg_user_mapping];
 	HeapTuple	tuple;
-	Oid			useId;
+	Oid			useId = InvalidOid;
 	Oid			umId;
 	ObjectAddress myself;
 	ObjectAddress referenced;
@@ -1099,7 +1081,9 @@ CreateUserMapping(CreateUserMappingStmt *stmt)
 
 	rel = heap_open(UserMappingRelationId, RowExclusiveLock);
 
-	useId = GetUserOidFromMapping(stmt->username, false);
+	/* "public" is mapped to userId = InvalidOid */
+	if (stmt->user->roltype != ROLESPEC_PUBLIC)
+		useId = get_rolespec_oid(stmt->user, false);
 
 	/* Check that the server exists. */
 	srv = GetForeignServerByName(stmt->servername, false);
@@ -1188,13 +1172,16 @@ AlterUserMapping(AlterUserMappingStmt *stmt)
 	Datum		repl_val[Natts_pg_user_mapping];
 	bool		repl_null[Natts_pg_user_mapping];
 	bool		repl_repl[Natts_pg_user_mapping];
-	Oid			useId;
+	Oid			useId = InvalidOid;
 	Oid			umId;
 	ForeignServer *srv;
 
 	rel = heap_open(UserMappingRelationId, RowExclusiveLock);
 
-	useId = GetUserOidFromMapping(stmt->username, false);
+	/* "public" is mapped to userId = InvalidOid */
+	if (stmt->user->roltype != ROLESPEC_PUBLIC)
+		useId = get_rolespec_oid(stmt->user, false);
+
 	srv = GetForeignServerByName(stmt->servername, false);
 
 	umId = GetSysCacheOid2(USERMAPPINGUSERSERVER,
@@ -1272,23 +1259,29 @@ Oid
 RemoveUserMapping(DropUserMappingStmt *stmt)
 {
 	ObjectAddress object;
-	Oid			useId;
+	Oid			useId = InvalidOid;
 	Oid			umId;
 	ForeignServer *srv;
 
-	useId = GetUserOidFromMapping(stmt->username, stmt->missing_ok);
-	srv = GetForeignServerByName(stmt->servername, true);
 
-	if (stmt->username && !OidIsValid(useId))
+	/* "public" is mapped to userId = InvalidOid */
+	if (stmt->user->roltype != ROLESPEC_PUBLIC)
 	{
-		/*
-		 * IF EXISTS specified, role not found and not public. Notice this and
-		 * leave.
-		 */
-		elog(NOTICE, "role \"%s\" does not exist, skipping", stmt->username);
-		return InvalidOid;
+		useId = get_rolespec_oid(stmt->user, stmt->missing_ok);
+		if (!OidIsValid(useId))
+		{
+			/*
+			 * IF EXISTS specified, role not found and not public. Notice this
+			 * and leave.
+			 */
+			elog(NOTICE, "role \"%s\" does not exist, skipping",
+				 stmt->user->str);
+			return InvalidOid;
+		}
 	}
 
+	srv = GetForeignServerByName(stmt->servername, true);
+
 	if (!srv)
 	{
 		if (!stmt->missing_ok)
diff --git a/src/backend/commands/schemacmds.c b/src/backend/commands/schemacmds.c
index 03f5514..3420d2d 100644
--- a/src/backend/commands/schemacmds.c
+++ b/src/backend/commands/schemacmds.c
@@ -21,6 +21,7 @@
 #include "catalog/dependency.h"
 #include "catalog/indexing.h"
 #include "catalog/namespace.h"
+#include "catalog/pg_authid.h"
 #include "catalog/objectaccess.h"
 #include "catalog/pg_namespace.h"
 #include "commands/dbcommands.h"
@@ -42,8 +43,8 @@ static void AlterSchemaOwner_internal(HeapTuple tup, Relation rel, Oid newOwnerI
 Oid
 CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
 {
-	const char *schemaName = stmt->schemaname;
-	const char *authId = stmt->authid;
+	const char	*schemaName = stmt->schemaname;
+	const RoleSpec *authrole = stmt->authrole;
 	Oid			namespaceId;
 	OverrideSearchPath *overridePath;
 	List	   *parsetree_list;
@@ -58,11 +59,32 @@ CreateSchemaCommand(CreateSchemaStmt *stmt, const char *queryString)
 	/*
 	 * Who is supposed to own the new schema?
 	 */
-	if (authId)
-		owner_uid = get_role_oid(authId, false);
+	if (authrole)
+	{
+		owner_uid = get_rolespec_oid(authrole, false);
+		if (!OidIsValid(owner_uid))
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("role \"%s\" does not exist", authrole->str)));
+			
+	}
 	else
 		owner_uid = saved_uid;
 
+	/* fill schema name with the user name if not specified */
+	if (!schemaName)
+	{
+		HeapTuple tuple;
+
+		tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(owner_uid));
+		if (!HeapTupleIsValid(tuple))
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("invalid role oid: %u", owner_uid)));
+		schemaName =
+			pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname));
+		ReleaseSysCache(tuple);
+	}
 	/*
 	 * 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
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 714a9f1..ce58196 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -3474,7 +3474,7 @@ ATExecCmd(List **wqueue, AlteredTableInfo *tab, Relation rel,
 			break;
 		case AT_ChangeOwner:	/* ALTER OWNER */
 			ATExecChangeOwner(RelationGetRelid(rel),
-							  get_role_oid(cmd->name, false),
+							  get_rolespec_oid(cmd->newowner, false),
 							  false, lockmode);
 			break;
 		case AT_ClusterOn:		/* CLUSTER ON */
@@ -9330,7 +9330,7 @@ AlterTableMoveAll(AlterTableMoveAllStmt *stmt)
 	HeapTuple	tuple;
 	Oid			orig_tablespaceoid;
 	Oid			new_tablespaceoid;
-	List	   *role_oids = roleNamesToIds(stmt->roles);
+	List	   *role_oids = roleSpecsToIds(stmt->roles);
 
 	/* Ensure we were not asked to move something we can't */
 	if (stmt->objtype != OBJECT_TABLE && stmt->objtype != OBJECT_INDEX &&
diff --git a/src/backend/commands/tablespace.c b/src/backend/commands/tablespace.c
index 616308b..6025dc6 100644
--- a/src/backend/commands/tablespace.c
+++ b/src/backend/commands/tablespace.c
@@ -252,7 +252,7 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
 
 	/* However, the eventual owner of the tablespace need not be */
 	if (stmt->owner)
-		ownerId = get_role_oid(stmt->owner, false);
+		ownerId = get_rolespec_oid(stmt->owner, false);
 	else
 		ownerId = GetUserId();
 
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
index 1a73fd8..377c7c6 100644
--- a/src/backend/commands/user.c
+++ b/src/backend/commands/user.c
@@ -310,13 +310,6 @@ CreateRole(CreateRoleStmt *stmt)
 					 errmsg("permission denied to create role")));
 	}
 
-	if (strcmp(stmt->role, "public") == 0 ||
-		strcmp(stmt->role, "none") == 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_RESERVED_NAME),
-				 errmsg("role name \"%s\" is reserved",
-						stmt->role)));
-
 	/*
 	 * Check the pg_authid relation to be certain the role doesn't already
 	 * exist.
@@ -445,10 +438,10 @@ CreateRole(CreateRoleStmt *stmt)
 	 * option, rolemembers don't.
 	 */
 	AddRoleMems(stmt->role, roleid,
-				adminmembers, roleNamesToIds(adminmembers),
+				adminmembers, roleSpecsToIds(adminmembers),
 				GetUserId(), true);
 	AddRoleMems(stmt->role, roleid,
-				rolemembers, roleNamesToIds(rolemembers),
+				rolemembers, roleSpecsToIds(rolemembers),
 				GetUserId(), false);
 
 	/* Post creation hook for new role */
@@ -481,6 +474,7 @@ AlterRole(AlterRoleStmt *stmt)
 	HeapTuple	tuple,
 				new_tuple;
 	ListCell   *option;
+	char	   *rolename = NULL;
 	char	   *password = NULL;	/* user password */
 	bool		encrypt_password = Password_encryption; /* encrypt password? */
 	char		encrypted_password[MD5_PASSWD_LEN + 1];
@@ -649,18 +643,25 @@ AlterRole(AlterRoleStmt *stmt)
 	pg_authid_rel = heap_open(AuthIdRelationId, RowExclusiveLock);
 	pg_authid_dsc = RelationGetDescr(pg_authid_rel);
 
-	tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
-	if (!HeapTupleIsValid(tuple))
+	roleid = get_rolespec_oid(stmt->role, false);
+	if (!OidIsValid(roleid))
 		ereport(ERROR,
 				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("role \"%s\" does not exist", stmt->role)));
-
-	roleid = HeapTupleGetOid(tuple);
+				 errmsg("role \"%s\" does not exist", stmt->role->str)));
 
 	/*
 	 * To mess with a superuser you gotta be superuser; else you need
 	 * createrole, or just want to change your own password
 	 */
+	tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+	if (!HeapTupleIsValid(tuple))
+		ereport(ERROR,
+				(errcode(ERRCODE_UNDEFINED_OBJECT),
+				 errmsg("invalid role oid: %u", roleid)));
+
+	rolename =
+		pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname));
+
 	if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper || issuper >= 0)
 	{
 		if (!superuser())
@@ -720,12 +721,12 @@ AlterRole(AlterRoleStmt *stmt)
 	 * Call the password checking hook if there is one defined
 	 */
 	if (check_password_hook && password)
-		(*check_password_hook) (stmt->role,
-								password,
-			   isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
-								validUntil_datum,
-								validUntil_null);
-
+		(*check_password_hook)(rolename ,
+							   password,
+			 isMD5(password) ? PASSWORD_TYPE_MD5 : PASSWORD_TYPE_PLAINTEXT,
+							   validUntil_datum,
+							   validUntil_null);
+	
 	/*
 	 * Build an updated tuple, perusing the information just obtained
 	 */
@@ -794,7 +795,7 @@ AlterRole(AlterRoleStmt *stmt)
 				CStringGetTextDatum(password);
 		else
 		{
-			if (!pg_md5_encrypt(password, stmt->role, strlen(stmt->role),
+			if (!pg_md5_encrypt(password, rolename, strlen(rolename),
 								encrypted_password))
 				elog(ERROR, "password encryption failed");
 			new_record[Anum_pg_authid_rolpassword - 1] =
@@ -841,12 +842,12 @@ AlterRole(AlterRoleStmt *stmt)
 		CommandCounterIncrement();
 
 	if (stmt->action == +1)		/* add members to role */
-		AddRoleMems(stmt->role, roleid,
-					rolemembers, roleNamesToIds(rolemembers),
+		AddRoleMems(rolename, roleid,
+					rolemembers, roleSpecsToIds(rolemembers),
 					GetUserId(), false);
 	else if (stmt->action == -1)	/* drop members from role */
-		DelRoleMems(stmt->role, roleid,
-					rolemembers, roleNamesToIds(rolemembers),
+		DelRoleMems(rolename, roleid,
+					rolemembers, roleSpecsToIds(rolemembers),
 					false);
 
 	/*
@@ -870,12 +871,20 @@ AlterRoleSet(AlterRoleSetStmt *stmt)
 
 	if (stmt->role)
 	{
-		roletuple = SearchSysCache1(AUTHNAME, PointerGetDatum(stmt->role));
+		roleid = get_rolespec_oid(stmt->role, false);
+
+		if (!OidIsValid(roleid))
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("role \"%s\" does not exist", stmt->role->str)));
+			
+
+		roletuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
 
 		if (!HeapTupleIsValid(roletuple))
 			ereport(ERROR,
 					(errcode(ERRCODE_UNDEFINED_OBJECT),
-					 errmsg("role \"%s\" does not exist", stmt->role)));
+					 errmsg("invalid role oid: %u", roleid)));
 
 		roleid = HeapTupleGetOid(roletuple);
 
@@ -1163,13 +1172,6 @@ RenameRole(const char *oldname, const char *newname)
 				(errcode(ERRCODE_DUPLICATE_OBJECT),
 				 errmsg("role \"%s\" already exists", newname)));
 
-	if (strcmp(newname, "public") == 0 ||
-		strcmp(newname, "none") == 0)
-		ereport(ERROR,
-				(errcode(ERRCODE_RESERVED_NAME),
-				 errmsg("role name \"%s\" is reserved",
-						newname)));
-
 	/*
 	 * createrole is enough privilege unless you want to mess with a superuser
 	 */
@@ -1240,11 +1242,11 @@ GrantRole(GrantRoleStmt *stmt)
 	ListCell   *item;
 
 	if (stmt->grantor)
-		grantor = get_role_oid(stmt->grantor, false);
+		grantor = get_rolespec_oid(stmt->grantor, false);
 	else
 		grantor = GetUserId();
 
-	grantee_ids = roleNamesToIds(stmt->grantee_roles);
+	grantee_ids = roleSpecsToIds(stmt->grantee_roles);
 
 	/* AccessShareLock is enough since we aren't modifying pg_authid */
 	pg_authid_rel = heap_open(AuthIdRelationId, AccessShareLock);
@@ -1293,7 +1295,7 @@ GrantRole(GrantRoleStmt *stmt)
 void
 DropOwnedObjects(DropOwnedStmt *stmt)
 {
-	List	   *role_ids = roleNamesToIds(stmt->roles);
+	List	   *role_ids = roleSpecsToIds(stmt->roles);
 	ListCell   *cell;
 
 	/* Check privileges */
@@ -1319,7 +1321,7 @@ DropOwnedObjects(DropOwnedStmt *stmt)
 void
 ReassignOwnedObjects(ReassignOwnedStmt *stmt)
 {
-	List	   *role_ids = roleNamesToIds(stmt->roles);
+	List	   *role_ids = roleSpecsToIds(stmt->roles);
 	ListCell   *cell;
 	Oid			newrole;
 
@@ -1335,7 +1337,7 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
 	}
 
 	/* Must have privileges on the receiving side too */
-	newrole = get_role_oid(stmt->newrole, false);
+	newrole = get_rolespec_oid(stmt->newrole, false);
 
 	if (!has_privs_of_role(GetUserId(), newrole))
 		ereport(ERROR,
@@ -1353,15 +1355,15 @@ ReassignOwnedObjects(ReassignOwnedStmt *stmt)
  * in the same order.
  */
 List *
-roleNamesToIds(List *memberNames)
+roleSpecsToIds(List *memberNames)
 {
 	List	   *result = NIL;
 	ListCell   *l;
 
 	foreach(l, memberNames)
 	{
-		char	   *rolename = strVal(lfirst(l));
-		Oid			roleid = get_role_oid(rolename, false);
+		RoleSpec   *rolespec = (RoleSpec*) lfirst(l);
+		Oid			roleid = get_rolespec_oid(rolespec, false);
 
 		result = lappend_oid(result, roleid);
 	}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index e76b5b3..effb062 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2493,6 +2493,17 @@ _copyXmlSerialize(const XmlSerialize *from)
 	return newnode;
 }
 
+static RoleSpec *
+_copyRoleSpec(const RoleSpec *from)
+{
+	RoleSpec *newnode = makeNode(RoleSpec);
+
+	COPY_SCALAR_FIELD(roltype);
+	COPY_STRING_FIELD(str);
+
+	return newnode;
+}
+
 static Query *
 _copyQuery(const Query *from)
 {
@@ -2639,6 +2650,7 @@ _copyAlterTableCmd(const AlterTableCmd *from)
 
 	COPY_SCALAR_FIELD(subtype);
 	COPY_STRING_FIELD(name);
+	COPY_NODE_FIELD(newowner);
 	COPY_NODE_FIELD(def);
 	COPY_SCALAR_FIELD(behavior);
 	COPY_SCALAR_FIELD(missing_ok);
@@ -2683,7 +2695,7 @@ _copyPrivGrantee(const PrivGrantee *from)
 {
 	PrivGrantee *newnode = makeNode(PrivGrantee);
 
-	COPY_STRING_FIELD(rolname);
+	COPY_NODE_FIELD(role);
 
 	return newnode;
 }
@@ -2719,7 +2731,7 @@ _copyGrantRoleStmt(const GrantRoleStmt *from)
 	COPY_NODE_FIELD(grantee_roles);
 	COPY_SCALAR_FIELD(is_grant);
 	COPY_SCALAR_FIELD(admin_opt);
-	COPY_STRING_FIELD(grantor);
+	COPY_NODE_FIELD(grantor);
 	COPY_SCALAR_FIELD(behavior);
 
 	return newnode;
@@ -3026,7 +3038,7 @@ _copyAlterOwnerStmt(const AlterOwnerStmt *from)
 	COPY_NODE_FIELD(relation);
 	COPY_NODE_FIELD(object);
 	COPY_NODE_FIELD(objarg);
-	COPY_STRING_FIELD(newowner);
+	COPY_NODE_FIELD(newowner);
 
 	return newnode;
 }
@@ -3411,7 +3423,7 @@ _copyCreateTableSpaceStmt(const CreateTableSpaceStmt *from)
 	CreateTableSpaceStmt *newnode = makeNode(CreateTableSpaceStmt);
 
 	COPY_STRING_FIELD(tablespacename);
-	COPY_STRING_FIELD(owner);
+	COPY_NODE_FIELD(owner);
 	COPY_STRING_FIELD(location);
 	COPY_NODE_FIELD(options);
 
@@ -3548,7 +3560,7 @@ _copyCreateUserMappingStmt(const CreateUserMappingStmt *from)
 {
 	CreateUserMappingStmt *newnode = makeNode(CreateUserMappingStmt);
 
-	COPY_STRING_FIELD(username);
+	COPY_NODE_FIELD(user);
 	COPY_STRING_FIELD(servername);
 	COPY_NODE_FIELD(options);
 
@@ -3560,7 +3572,7 @@ _copyAlterUserMappingStmt(const AlterUserMappingStmt *from)
 {
 	AlterUserMappingStmt *newnode = makeNode(AlterUserMappingStmt);
 
-	COPY_STRING_FIELD(username);
+	COPY_NODE_FIELD(user);
 	COPY_STRING_FIELD(servername);
 	COPY_NODE_FIELD(options);
 
@@ -3572,7 +3584,7 @@ _copyDropUserMappingStmt(const DropUserMappingStmt *from)
 {
 	DropUserMappingStmt *newnode = makeNode(DropUserMappingStmt);
 
-	COPY_STRING_FIELD(username);
+	COPY_NODE_FIELD(user);
 	COPY_STRING_FIELD(servername);
 	COPY_SCALAR_FIELD(missing_ok);
 
@@ -3685,7 +3697,7 @@ _copyAlterRoleStmt(const AlterRoleStmt *from)
 {
 	AlterRoleStmt *newnode = makeNode(AlterRoleStmt);
 
-	COPY_STRING_FIELD(role);
+	COPY_NODE_FIELD(role);
 	COPY_NODE_FIELD(options);
 	COPY_SCALAR_FIELD(action);
 
@@ -3697,7 +3709,7 @@ _copyAlterRoleSetStmt(const AlterRoleSetStmt *from)
 {
 	AlterRoleSetStmt *newnode = makeNode(AlterRoleSetStmt);
 
-	COPY_STRING_FIELD(role);
+	COPY_NODE_FIELD(role);
 	COPY_STRING_FIELD(database);
 	COPY_NODE_FIELD(setstmt);
 
@@ -3758,7 +3770,7 @@ _copyCreateSchemaStmt(const CreateSchemaStmt *from)
 	CreateSchemaStmt *newnode = makeNode(CreateSchemaStmt);
 
 	COPY_STRING_FIELD(schemaname);
-	COPY_STRING_FIELD(authid);
+	COPY_NODE_FIELD(authrole);
 	COPY_NODE_FIELD(schemaElts);
 	COPY_SCALAR_FIELD(if_not_exists);
 
@@ -3843,7 +3855,7 @@ _copyReassignOwnedStmt(const ReassignOwnedStmt *from)
 	ReassignOwnedStmt *newnode = makeNode(ReassignOwnedStmt);
 
 	COPY_NODE_FIELD(roles);
-	COPY_STRING_FIELD(newrole);
+	COPY_NODE_FIELD(newrole);
 
 	return newnode;
 }
@@ -4729,6 +4741,9 @@ copyObject(const void *from)
 		case T_XmlSerialize:
 			retval = _copyXmlSerialize(from);
 			break;
+		case T_RoleSpec:
+			retval = _copyRoleSpec(from);
+			break;
 
 		default:
 			elog(ERROR, "unrecognized node type: %d", (int) nodeTag(from));
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index d5db71d..42a7f53 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -971,6 +971,7 @@ _equalAlterTableCmd(const AlterTableCmd *a, const AlterTableCmd *b)
 {
 	COMPARE_SCALAR_FIELD(subtype);
 	COMPARE_STRING_FIELD(name);
+	COMPARE_NODE_FIELD(newowner);
 	COMPARE_NODE_FIELD(def);
 	COMPARE_SCALAR_FIELD(behavior);
 	COMPARE_SCALAR_FIELD(missing_ok);
@@ -1009,7 +1010,7 @@ _equalGrantStmt(const GrantStmt *a, const GrantStmt *b)
 static bool
 _equalPrivGrantee(const PrivGrantee *a, const PrivGrantee *b)
 {
-	COMPARE_STRING_FIELD(rolname);
+	COMPARE_NODE_FIELD(role);
 
 	return true;
 }
@@ -1039,7 +1040,7 @@ _equalGrantRoleStmt(const GrantRoleStmt *a, const GrantRoleStmt *b)
 	COMPARE_NODE_FIELD(grantee_roles);
 	COMPARE_SCALAR_FIELD(is_grant);
 	COMPARE_SCALAR_FIELD(admin_opt);
-	COMPARE_STRING_FIELD(grantor);
+	COMPARE_NODE_FIELD(grantor);
 	COMPARE_SCALAR_FIELD(behavior);
 
 	return true;
@@ -1292,7 +1293,7 @@ _equalAlterOwnerStmt(const AlterOwnerStmt *a, const AlterOwnerStmt *b)
 	COMPARE_NODE_FIELD(relation);
 	COMPARE_NODE_FIELD(object);
 	COMPARE_NODE_FIELD(objarg);
-	COMPARE_STRING_FIELD(newowner);
+	COMPARE_NODE_FIELD(newowner);
 
 	return true;
 }
@@ -1614,7 +1615,7 @@ static bool
 _equalCreateTableSpaceStmt(const CreateTableSpaceStmt *a, const CreateTableSpaceStmt *b)
 {
 	COMPARE_STRING_FIELD(tablespacename);
-	COMPARE_STRING_FIELD(owner);
+	COMPARE_NODE_FIELD(owner);
 	COMPARE_STRING_FIELD(location);
 	COMPARE_NODE_FIELD(options);
 
@@ -1731,7 +1732,7 @@ _equalAlterForeignServerStmt(const AlterForeignServerStmt *a, const AlterForeign
 static bool
 _equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMappingStmt *b)
 {
-	COMPARE_STRING_FIELD(username);
+	COMPARE_NODE_FIELD(user);
 	COMPARE_STRING_FIELD(servername);
 	COMPARE_NODE_FIELD(options);
 
@@ -1741,7 +1742,7 @@ _equalCreateUserMappingStmt(const CreateUserMappingStmt *a, const CreateUserMapp
 static bool
 _equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMappingStmt *b)
 {
-	COMPARE_STRING_FIELD(username);
+	COMPARE_NODE_FIELD(user);
 	COMPARE_STRING_FIELD(servername);
 	COMPARE_NODE_FIELD(options);
 
@@ -1751,7 +1752,7 @@ _equalAlterUserMappingStmt(const AlterUserMappingStmt *a, const AlterUserMapping
 static bool
 _equalDropUserMappingStmt(const DropUserMappingStmt *a, const DropUserMappingStmt *b)
 {
-	COMPARE_STRING_FIELD(username);
+	COMPARE_NODE_FIELD(user);
 	COMPARE_STRING_FIELD(servername);
 	COMPARE_SCALAR_FIELD(missing_ok);
 
@@ -1849,7 +1850,7 @@ _equalCreateRoleStmt(const CreateRoleStmt *a, const CreateRoleStmt *b)
 static bool
 _equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
 {
-	COMPARE_STRING_FIELD(role);
+	COMPARE_NODE_FIELD(role);
 	COMPARE_NODE_FIELD(options);
 	COMPARE_SCALAR_FIELD(action);
 
@@ -1859,7 +1860,7 @@ _equalAlterRoleStmt(const AlterRoleStmt *a, const AlterRoleStmt *b)
 static bool
 _equalAlterRoleSetStmt(const AlterRoleSetStmt *a, const AlterRoleSetStmt *b)
 {
-	COMPARE_STRING_FIELD(role);
+	COMPARE_NODE_FIELD(role);
 	COMPARE_STRING_FIELD(database);
 	COMPARE_NODE_FIELD(setstmt);
 
@@ -1910,7 +1911,7 @@ static bool
 _equalCreateSchemaStmt(const CreateSchemaStmt *a, const CreateSchemaStmt *b)
 {
 	COMPARE_STRING_FIELD(schemaname);
-	COMPARE_STRING_FIELD(authid);
+	COMPARE_NODE_FIELD(authrole);
 	COMPARE_NODE_FIELD(schemaElts);
 	COMPARE_SCALAR_FIELD(if_not_exists);
 
@@ -1981,7 +1982,7 @@ static bool
 _equalReassignOwnedStmt(const ReassignOwnedStmt *a, const ReassignOwnedStmt *b)
 {
 	COMPARE_NODE_FIELD(roles);
-	COMPARE_STRING_FIELD(newrole);
+	COMPARE_NODE_FIELD(newrole);
 
 	return true;
 }
@@ -2453,6 +2454,15 @@ _equalXmlSerialize(const XmlSerialize *a, const XmlSerialize *b)
 	return true;
 }
 
+static bool
+_equalRoleSpec(const RoleSpec *a, const RoleSpec *b)
+{
+	COMPARE_SCALAR_FIELD(roltype);
+	COMPARE_STRING_FIELD(str);
+
+	return true;
+}
+
 /*
  * Stuff from pg_list.h
  */
@@ -3163,6 +3173,9 @@ equal(const void *a, const void *b)
 		case T_XmlSerialize:
 			retval = _equalXmlSerialize(a, b);
 			break;
+		case T_RoleSpec:
+			retval = _equalRoleSpec(a, b);
+			break;
 
 		default:
 			elog(ERROR, "unrecognized node type: %d",
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index bd180e7..4d9e374 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -192,6 +192,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 	int					ival;
 	char				*str;
 	const char			*keyword;
+	RoleSpec			*rolespec;
 
 	char				chr;
 	bool				boolean;
@@ -291,7 +292,7 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 
 %type <str>		opt_type
 %type <str>		foreign_server_version opt_foreign_server_version
-%type <str>		auth_ident
+%type <rolespec>	auth_ident
 %type <str>		opt_in_database
 
 %type <str>		OptSchemaName
@@ -474,7 +475,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 
 %type <ival>	Iconst SignedIconst
 %type <str>		Sconst comment_text notify_payload
-%type <str>		RoleId opt_granted_by opt_boolean_or_string
+%type <rolespec>	RoleId opt_granted_by
+%type <str>     opt_boolean_or_string
 %type <list>	var_list
 %type <str>		ColId ColLabel var_name type_function_name param_name
 %type <str>		NonReservedWord NonReservedWord_or_Sconst
@@ -494,7 +496,8 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 
 %type <list>	constraints_set_list
 %type <boolean> constraints_set_mode
-%type <str>		OptTableSpace OptConsTableSpace OptTableSpaceOwner
+%type <str>		OptTableSpace OptConsTableSpace
+%type <rolespec>  OptTableSpaceOwner
 %type <ival>	opt_check_option
 
 %type <str>		opt_provider security_label
@@ -864,8 +867,14 @@ CreateRoleStmt:
 			CREATE ROLE RoleId opt_with OptRoleList
 				{
 					CreateRoleStmt *n = makeNode(CreateRoleStmt);
+					RoleSpec	   *rolspc = $3;
+					if (rolspc->roltype != ROLESPEC_CSTRING)
+						ereport(ERROR,
+								(errcode(ERRCODE_SYNTAX_ERROR),
+								 errmsg("role name should not be a keyword nor reserved name."),
+								 parser_errposition(@3)));
 					n->stmt_type = ROLESTMT_ROLE;
-					n->role = $3;
+					n->role = rolspc->str;
 					n->options = $5;
 					$$ = (Node *)n;
 				}
@@ -1021,8 +1030,14 @@ CreateUserStmt:
 			CREATE USER RoleId opt_with OptRoleList
 				{
 					CreateRoleStmt *n = makeNode(CreateRoleStmt);
+					RoleSpec	   *rolspc = $3;
+					if (rolspc->roltype != ROLESPEC_CSTRING)
+						ereport(ERROR,
+								(errcode(ERRCODE_SYNTAX_ERROR),
+								 errmsg("role name should not be a keyword nor reserved name."),
+								 parser_errposition(@3)));
 					n->stmt_type = ROLESTMT_USER;
-					n->role = $3;
+					n->role = rolspc->str;
 					n->options = $5;
 					$$ = (Node *)n;
 				}
@@ -1164,8 +1179,14 @@ CreateGroupStmt:
 			CREATE GROUP_P RoleId opt_with OptRoleList
 				{
 					CreateRoleStmt *n = makeNode(CreateRoleStmt);
+					RoleSpec	   *rolspc = $3;
+					if (rolspc->roltype != ROLESPEC_CSTRING)
+						ereport(ERROR,
+								(errcode(ERRCODE_SYNTAX_ERROR),
+								 errmsg("role name should not be a keyword nor reserved name."),
+								 parser_errposition(@3)));
 					n->stmt_type = ROLESTMT_GROUP;
-					n->role = $3;
+					n->role = rolspc->str;
 					n->options = $5;
 					$$ = (Node *)n;
 				}
@@ -1231,11 +1252,8 @@ CreateSchemaStmt:
 				{
 					CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
 					/* One can omit the schema name or the authorization id. */
-					if ($3 != NULL)
-						n->schemaname = $3;
-					else
-						n->schemaname = $5;
-					n->authid = $5;
+					n->schemaname = $3;
+					n->authrole = $5;
 					n->schemaElts = $6;
 					n->if_not_exists = false;
 					$$ = (Node *)n;
@@ -1245,7 +1263,7 @@ CreateSchemaStmt:
 					CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
 					/* ...but not both */
 					n->schemaname = $3;
-					n->authid = NULL;
+					n->authrole = NULL;
 					n->schemaElts = $4;
 					n->if_not_exists = false;
 					$$ = (Node *)n;
@@ -1254,11 +1272,8 @@ CreateSchemaStmt:
 				{
 					CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
 					/* One can omit the schema name or the authorization id. */
-					if ($6 != NULL)
-						n->schemaname = $6;
-					else
-						n->schemaname = $8;
-					n->authid = $8;
+					n->schemaname = $6;
+					n->authrole = $8;
 					if ($9 != NIL)
 						ereport(ERROR,
 								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -1273,7 +1288,7 @@ CreateSchemaStmt:
 					CreateSchemaStmt *n = makeNode(CreateSchemaStmt);
 					/* ...but not both */
 					n->schemaname = $6;
-					n->authid = NULL;
+					n->authrole = NULL;
 					if ($7 != NIL)
 						ereport(ERROR,
 								(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -2263,7 +2278,7 @@ alter_table_cmd:
 				{
 					AlterTableCmd *n = makeNode(AlterTableCmd);
 					n->subtype = AT_ChangeOwner;
-					n->name = $3;
+					n->newowner = $3;
 					$$ = (Node *)n;
 				}
 			/* ALTER TABLE <name> SET TABLESPACE <tablespacename> */
@@ -3727,7 +3742,7 @@ CreateTableSpaceStmt: CREATE TABLESPACE name OptTableSpaceOwner LOCATION Sconst
 				}
 		;
 
-OptTableSpaceOwner: OWNER name			{ $$ = $2; }
+OptTableSpaceOwner: OWNER RoleId		{ $$ = $2; }
 			| /*EMPTY */				{ $$ = NULL; }
 		;
 
@@ -4449,7 +4464,7 @@ import_qualification:
 CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_generic_options
 				{
 					CreateUserMappingStmt *n = makeNode(CreateUserMappingStmt);
-					n->username = $5;
+					n->user = $5;
 					n->servername = $7;
 					n->options = $8;
 					$$ = (Node *) n;
@@ -4458,9 +4473,19 @@ CreateUserMappingStmt: CREATE USER MAPPING FOR auth_ident SERVER name create_gen
 
 /* User mapping authorization identifier */
 auth_ident:
-			CURRENT_USER	{ $$ = "current_user"; }
-		|	USER			{ $$ = "current_user"; }
-		|	RoleId			{ $$ = (strcmp($1, "public") == 0) ? NULL : $1; }
+			RoleId
+			{ $$ = $1; }
+			/*
+			 * The keyword USER won't be appear in other syntxes so it is
+			 * processed here, not at RoleId.
+			 */
+			|	USER
+			{
+				RoleSpec *n = makeNode(RoleSpec);
+				n->roltype = ROLESPEC_CURRENT_USER;
+				n->str = pstrdup($1);
+				$$ = n;
+			}
 		;
 
 /*****************************************************************************
@@ -4473,7 +4498,7 @@ auth_ident:
 DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
 				{
 					DropUserMappingStmt *n = makeNode(DropUserMappingStmt);
-					n->username = $5;
+					n->user = $5;
 					n->servername = $7;
 					n->missing_ok = false;
 					$$ = (Node *) n;
@@ -4481,7 +4506,7 @@ DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
 				|  DROP USER MAPPING IF_P EXISTS FOR auth_ident SERVER name
 				{
 					DropUserMappingStmt *n = makeNode(DropUserMappingStmt);
-					n->username = $7;
+					n->user = $7;
 					n->servername = $9;
 					n->missing_ok = true;
 					$$ = (Node *) n;
@@ -4498,7 +4523,7 @@ DropUserMappingStmt: DROP USER MAPPING FOR auth_ident SERVER name
 AlterUserMappingStmt: ALTER USER MAPPING FOR auth_ident SERVER name alter_generic_options
 				{
 					AlterUserMappingStmt *n = makeNode(AlterUserMappingStmt);
-					n->username = $5;
+					n->user = $5;
 					n->servername = $7;
 					n->options = $8;
 					$$ = (Node *) n;
@@ -5403,7 +5428,7 @@ DropOwnedStmt:
 		;
 
 ReassignOwnedStmt:
-			REASSIGN OWNED BY role_list TO name
+			REASSIGN OWNED BY role_list TO RoleId
 				{
 					ReassignOwnedStmt *n = makeNode(ReassignOwnedStmt);
 					n->roles = $4;
@@ -6221,21 +6246,27 @@ grantee_list:
 grantee:	RoleId
 				{
 					PrivGrantee *n = makeNode(PrivGrantee);
-					/* This hack lets us avoid reserving PUBLIC as a keyword*/
-					if (strcmp($1, "public") == 0)
-						n->rolname = NULL;
-					else
-						n->rolname = $1;
+					RoleSpec		*rolspc = $1;
+					if (rolspc->roltype == ROLESPEC_NONE)
+						ereport(ERROR,
+								(errcode(ERRCODE_SYNTAX_ERROR),
+								 errmsg("%s cannot be used as grantee name",
+										rolspc->str)));
+					n->role = rolspc;
 					$$ = (Node *)n;
 				}
 			| GROUP_P RoleId
+				/* Treat GROUP PUBLIC as a synonym for PUBLIC */
 				{
 					PrivGrantee *n = makeNode(PrivGrantee);
-					/* Treat GROUP PUBLIC as a synonym for PUBLIC */
-					if (strcmp($2, "public") == 0)
-						n->rolname = NULL;
-					else
-						n->rolname = $2;
+					RoleSpec		*rolspc = $2;
+
+					if (rolspc->roltype == ROLESPEC_NONE)
+						ereport(ERROR,
+								(errcode(ERRCODE_SYNTAX_ERROR),
+								 errmsg("%s cannot be used as grantee name",
+										rolspc->str)));
+					n->role = rolspc;
 					$$ = (Node *)n;
 				}
 		;
@@ -7340,9 +7371,19 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
 			| ALTER GROUP_P RoleId RENAME TO RoleId
 				{
 					RenameStmt *n = makeNode(RenameStmt);
+					RoleSpec	   *nold = $3;
+					RoleSpec	   *nnew = $6;
+					if (nold->roltype != ROLESPEC_CSTRING ||
+						nnew->roltype != ROLESPEC_CSTRING)
+						ereport(ERROR,
+								(errcode(ERRCODE_SYNTAX_ERROR),
+								 errmsg("role name should not be a keyword nor reserved name."),
+								 parser_errposition(
+									 nold->roltype != ROLESPEC_CSTRING ?
+									 @3 : @6)));
 					n->renameType = OBJECT_ROLE;
-					n->subname = $3;
-					n->newname = $6;
+					n->subname = nold->str;
+					n->newname = nnew->str;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -7640,18 +7681,38 @@ RenameStmt: ALTER AGGREGATE func_name aggr_args RENAME TO name
 			| ALTER ROLE RoleId RENAME TO RoleId
 				{
 					RenameStmt *n = makeNode(RenameStmt);
+					RoleSpec	   *nold = $3;
+					RoleSpec	   *nnew = $6;
+					if (nold->roltype != ROLESPEC_CSTRING ||
+						nnew->roltype != ROLESPEC_CSTRING)
+						ereport(ERROR,
+								(errcode(ERRCODE_SYNTAX_ERROR),
+								 errmsg("role name should not be a keyword nor reserved name."),
+								 parser_errposition(
+									 nold->roltype != ROLESPEC_CSTRING ?
+									 @3 : @6)));
 					n->renameType = OBJECT_ROLE;
-					n->subname = $3;
-					n->newname = $6;
+					n->subname = nold->str;
+					n->newname = nnew->str;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
 			| ALTER USER RoleId RENAME TO RoleId
 				{
 					RenameStmt *n = makeNode(RenameStmt);
+					RoleSpec	   *nold = $3;
+					RoleSpec	   *nnew = $6;
+					if (nold->roltype != ROLESPEC_CSTRING ||
+						nnew->roltype != ROLESPEC_CSTRING)
+						ereport(ERROR,
+								(errcode(ERRCODE_SYNTAX_ERROR),
+								 errmsg("role name should not be a keyword nor reserved name."),
+								 parser_errposition(
+									 nold->roltype != ROLESPEC_CSTRING ?
+									 @3 : @6)));
 					n->renameType = OBJECT_ROLE;
-					n->subname = $3;
-					n->newname = $6;
+					n->subname = nold->str;
+					n->newname = nnew->str;
 					n->missing_ok = false;
 					$$ = (Node *)n;
 				}
@@ -10716,7 +10777,7 @@ opt_float:	'(' Iconst ')'
 					if ($2 < 1)
 						ereport(ERROR,
 								(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
-								 errmsg("precision for type float must be at least 1 bit"),
+								 errmsg("recision for type float must be at least 1 bit"),
 								 parser_errposition(@2)));
 					else if ($2 <= 24)
 						$$ = SystemTypeName("float4");
@@ -12946,12 +13007,45 @@ AexprConst: Iconst
 
 Iconst:		ICONST									{ $$ = $1; };
 Sconst:		SCONST									{ $$ = $1; };
-RoleId:		NonReservedWord							{ $$ = $1; };
+RoleId:		NonReservedWord
+					{
+						/*
+						 * The name "public" and "none" are decided not to be
+						 * keywords. They cannot be used as identifier by any
+						 * means as the result.
+						 */
+						RoleSpec *n = makeNode(RoleSpec);
+						char   *w = pstrdup($1);
+						if (strcmp(w, "public") == 0)
+							n->roltype = ROLESPEC_PUBLIC;
+						else if (strcmp(w, "none") == 0)
+							n->roltype = ROLESPEC_NONE;
+						else
+							n->roltype = ROLESPEC_CSTRING;
+						n->str = w;
+						$$ = n;
+					}
+			| CURRENT_USER
+					{
+						RoleSpec *n = makeNode(RoleSpec);
+						n->roltype = ROLESPEC_CURRENT_USER;
+						n->str = pstrdup($1);
+						$$ = n;
+					}
+			| SESSION_USER
+					{
+						RoleSpec *n = makeNode(RoleSpec);
+						n->roltype = ROLESPEC_SESSION_USER;
+						n->str = pstrdup($1);
+						$$ = n;
+					}
+		;
+
 
 role_list:	RoleId
-					{ $$ = list_make1(makeString($1)); }
+					{ $$ = list_make1($1); }
 			| role_list ',' RoleId
-					{ $$ = lappend($1, makeString($3)); }
+					{ $$ = lappend($1, $3); }
 		;
 
 SignedIconst: Iconst								{ $$ = $1; }
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 7c1939f..1edc112 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -90,7 +90,7 @@ typedef struct
 {
 	const char *stmtType;		/* "CREATE SCHEMA" or "ALTER SCHEMA" */
 	char	   *schemaname;		/* name of schema */
-	char	   *authid;			/* owner of schema */
+	RoleSpec   *authrole;		/* owner of schema */
 	List	   *sequences;		/* CREATE SEQUENCE items */
 	List	   *tables;			/* CREATE TABLE items */
 	List	   *views;			/* CREATE VIEW items */
@@ -2687,7 +2687,7 @@ transformCreateSchemaStmt(CreateSchemaStmt *stmt)
 
 	cxt.stmtType = "CREATE SCHEMA";
 	cxt.schemaname = stmt->schemaname;
-	cxt.authid = stmt->authid;
+	cxt.authrole = stmt->authrole;
 	cxt.sequences = NIL;
 	cxt.tables = NIL;
 	cxt.views = NIL;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index dc6eb2c..4a1110e 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -5133,3 +5133,37 @@ get_role_oid_or_public(const char *rolname)
 
 	return get_role_oid(rolname, false);
 }
+
+Oid
+get_rolespec_oid(const RoleSpec *rolname, bool missing_ok)
+{
+	Oid			oid;
+
+	switch (rolname->roltype)
+	{
+	case ROLESPEC_CSTRING:
+		oid = get_role_oid(rolname->str, missing_ok);
+		break;
+	case ROLESPEC_CURRENT_USER:
+		oid = GetUserId();
+		break;
+	case ROLESPEC_SESSION_USER:
+		oid = GetSessionUserId();
+		break;
+
+	/* special roles which should not exist */
+	case ROLESPEC_PUBLIC:
+	case ROLESPEC_NONE:
+		if (!missing_ok)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("role \"%s\" does not exist", rolname->str)));
+		oid = InvalidOid;
+		break;
+
+	default:
+		elog(ERROR, "Unexpected nameid for role: %d", rolname->roltype);
+	}
+
+	return oid;
+}
diff --git a/src/include/commands/user.h b/src/include/commands/user.h
index d766851..e83afab 100644
--- a/src/include/commands/user.h
+++ b/src/include/commands/user.h
@@ -30,6 +30,6 @@ extern void GrantRole(GrantRoleStmt *stmt);
 extern Oid	RenameRole(const char *oldname, const char *newname);
 extern void DropOwnedObjects(DropOwnedStmt *stmt);
 extern void ReassignOwnedObjects(ReassignOwnedStmt *stmt);
-extern List *roleNamesToIds(List *memberNames);
+extern List *roleSpecsToIds(List *memberNames);
 
 #endif   /* USER_H */
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
index bc71fea..fdb217d 100644
--- a/src/include/nodes/nodes.h
+++ b/src/include/nodes/nodes.h
@@ -413,6 +413,7 @@ typedef enum NodeTag
 	T_XmlSerialize,
 	T_WithClause,
 	T_CommonTableExpr,
+	T_RoleSpec,
 
 	/*
 	 * TAGS FOR REPLICATION GRAMMAR PARSE NODES (replnodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index 3e4f815..02d4c88 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -278,6 +278,29 @@ typedef struct CollateClause
 } CollateClause;
 
 /*
+ * RoleSpec - Stroes role name or id of some special values.
+ *
+ * "public" and "none" are the special role which cannot be used as role name
+ * from historical reasons.
+ */
+typedef enum RoleSpecTypes
+{
+	ROLESPEC_CSTRING,		/* role name is stored in str */
+	ROLESPEC_CURRENT_USER,	/* role spec is CURRENT_USER */
+	ROLESPEC_SESSION_USER,	/* role spec is SESSION_USER */
+	ROLESPEC_PUBLIC,		/* role name is "public", a special value */
+	ROLESPEC_NONE			/* role name is "none", a special value and this
+							 * is simply unusable at all. */
+} RoleSpecTypes;
+
+typedef struct RoleSpec
+{
+	NodeTag		  type;
+	RoleSpecTypes roltype;	/* Type of this rolespec */
+	char	 	 *str;		/* Will be filled only for ROLESPEC_CSTRING */
+} RoleSpec;
+
+/*
  * FuncCall - a function or aggregate invocation
  *
  * agg_order (if not NIL) indicates we saw 'foo(... ORDER BY ...)', or if
@@ -1254,7 +1277,7 @@ typedef struct CreateSchemaStmt
 {
 	NodeTag		type;
 	char	   *schemaname;		/* the name of the schema to create */
-	char	   *authid;			/* the owner of the created schema */
+	RoleSpec   *authrole;		/* the owner of the created schema */
 	List	   *schemaElts;		/* schema components (list of parsenodes) */
 	bool		if_not_exists;	/* just do nothing if schema already exists? */
 } CreateSchemaStmt;
@@ -1353,7 +1376,8 @@ typedef struct AlterTableCmd	/* one subcommand of an ALTER TABLE */
 	NodeTag		type;
 	AlterTableType subtype;		/* Type of table alteration to apply */
 	char	   *name;			/* column, constraint, or trigger to act on,
-								 * or new owner or tablespace */
+								 * or tablespace */
+	RoleSpec   *newowner;		/* new owner could be special values */
 	Node	   *def;			/* definition of new column, index,
 								 * constraint, or parent table */
 	DropBehavior behavior;		/* RESTRICT or CASCADE for DROP cases */
@@ -1433,7 +1457,7 @@ typedef struct GrantStmt
 typedef struct PrivGrantee
 {
 	NodeTag		type;
-	char	   *rolname;		/* if NULL then PUBLIC */
+	RoleSpec   *role;		/* if NULL then PUBLIC */
 } PrivGrantee;
 
 /*
@@ -1478,7 +1502,7 @@ typedef struct GrantRoleStmt
 	List	   *grantee_roles;	/* list of member roles to add/delete */
 	bool		is_grant;		/* true = GRANT, false = REVOKE */
 	bool		admin_opt;		/* with admin option */
-	char	   *grantor;		/* set grantor to other than current role */
+	RoleSpec   *grantor;		/* set grantor to other than current role */
 	DropBehavior behavior;		/* drop behavior (for REVOKE) */
 } GrantRoleStmt;
 
@@ -1690,7 +1714,7 @@ typedef struct CreateTableSpaceStmt
 {
 	NodeTag		type;
 	char	   *tablespacename;
-	char	   *owner;
+	RoleSpec   *owner;
 	char	   *location;
 	List	   *options;
 } CreateTableSpaceStmt;
@@ -1816,7 +1840,7 @@ typedef struct CreateForeignTableStmt
 typedef struct CreateUserMappingStmt
 {
 	NodeTag		type;
-	char	   *username;		/* username or PUBLIC/CURRENT_USER */
+	RoleSpec   *user;			/* user role */
 	char	   *servername;		/* server name */
 	List	   *options;		/* generic options to server */
 } CreateUserMappingStmt;
@@ -1824,7 +1848,7 @@ typedef struct CreateUserMappingStmt
 typedef struct AlterUserMappingStmt
 {
 	NodeTag		type;
-	char	   *username;		/* username or PUBLIC/CURRENT_USER */
+	RoleSpec   *user;			/* user role */
 	char	   *servername;		/* server name */
 	List	   *options;		/* generic options to server */
 } AlterUserMappingStmt;
@@ -1832,7 +1856,7 @@ typedef struct AlterUserMappingStmt
 typedef struct DropUserMappingStmt
 {
 	NodeTag		type;
-	char	   *username;		/* username or PUBLIC/CURRENT_USER */
+	RoleSpec   *user;			/* user role */
 	char	   *servername;		/* server name */
 	bool		missing_ok;		/* ignore missing mappings */
 } DropUserMappingStmt;
@@ -1982,7 +2006,7 @@ typedef struct CreateRoleStmt
 typedef struct AlterRoleStmt
 {
 	NodeTag		type;
-	char	   *role;			/* role name */
+	RoleSpec   *role;			/* role */
 	List	   *options;		/* List of DefElem nodes */
 	int			action;			/* +1 = add members, -1 = drop members */
 } AlterRoleStmt;
@@ -1990,7 +2014,7 @@ typedef struct AlterRoleStmt
 typedef struct AlterRoleSetStmt
 {
 	NodeTag		type;
-	char	   *role;			/* role name */
+	RoleSpec   *role;			/* role */
 	char	   *database;		/* database name, or NULL */
 	VariableSetStmt *setstmt;	/* SET or RESET subcommand */
 } AlterRoleSetStmt;
@@ -2365,7 +2389,7 @@ typedef struct AlterOwnerStmt
 	RangeVar   *relation;		/* in case it's a table */
 	List	   *object;			/* in case it's some other object */
 	List	   *objarg;			/* argument types, if applicable */
-	char	   *newowner;		/* the new owner */
+	RoleSpec   *newowner;		/* the new owner */
 } AlterOwnerStmt;
 
 
@@ -2813,7 +2837,7 @@ typedef struct ReassignOwnedStmt
 {
 	NodeTag		type;
 	List	   *roles;
-	char	   *newrole;
+	RoleSpec   *newrole;
 } ReassignOwnedStmt;
 
 /*
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
index a8e3164..2863183 100644
--- a/src/include/utils/acl.h
+++ b/src/include/utils/acl.h
@@ -229,7 +229,7 @@ extern bool is_admin_of_role(Oid member, Oid role);
 extern void check_is_member_of_role(Oid member, Oid role);
 extern Oid	get_role_oid(const char *rolname, bool missing_ok);
 extern Oid	get_role_oid_or_public(const char *rolname);
-
+extern Oid  get_rolespec_oid(const RoleSpec *role, bool missing_ok);
 extern void select_best_grantor(Oid roleId, AclMode privileges,
 					const Acl *acl, Oid ownerId,
 					Oid *grantorId, AclMode *grantOptions);
-- 
2.1.0.GIT

-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to