>From 9d0f654d8930f8c9b15072f9a4238f9d5fa5f600 Mon Sep 17 00:00:00 2001
From: Kyotaro Horiguchi <horiguchi.kyotaro@lab.ntt.co.jp>
Date: Thu, 9 Apr 2015 17:15:26 +0900
Subject: [PATCH] Fix regroleout's behavior following other out functions for
 reg* types.

regroleout raises signal for nonexistent role oids, but this is
different behavior from other reg* types. Fixed the behavior as the
same as the other reg* types.
---
 contrib/spi/insert_username.c       |  2 +-
 contrib/spi/timetravel.c            |  2 +-
 src/backend/catalog/objectaddress.c | 20 ++++++++++----------
 src/backend/utils/adt/acl.c         |  2 +-
 src/backend/utils/adt/name.c        |  4 ++--
 src/backend/utils/adt/regproc.c     |  8 +++++++-
 src/backend/utils/init/miscinit.c   | 24 +++++++++++++++---------
 src/include/foreign/foreign.h       |  2 +-
 src/include/miscadmin.h             |  2 +-
 9 files changed, 39 insertions(+), 27 deletions(-)

diff --git a/contrib/spi/insert_username.c b/contrib/spi/insert_username.c
index 8752078..3812525 100644
--- a/contrib/spi/insert_username.c
+++ b/contrib/spi/insert_username.c
@@ -79,7 +79,7 @@ insert_username(PG_FUNCTION_ARGS)
 						args[0], relname)));
 
 	/* create fields containing name */
-	newval = CStringGetTextDatum(GetUserNameFromId(GetUserId()));
+	newval = CStringGetTextDatum(GetUserNameFromId(GetUserId(), false));
 
 	/* construct new tuple */
 	rettuple = SPI_modifytuple(rel, rettuple, 1, &attnum, &newval, NULL);
diff --git a/contrib/spi/timetravel.c b/contrib/spi/timetravel.c
index 0699438..e125986 100644
--- a/contrib/spi/timetravel.c
+++ b/contrib/spi/timetravel.c
@@ -174,7 +174,7 @@ timetravel(PG_FUNCTION_ARGS)
 	}
 
 	/* create fields containing name */
-	newuser = CStringGetTextDatum(GetUserNameFromId(GetUserId()));
+	newuser = CStringGetTextDatum(GetUserNameFromId(GetUserId(), false));
 
 	nulltext = (Datum) NULL;
 
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 30cb699..4cf46f2 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2777,7 +2777,7 @@ getObjectDescription(const ObjectAddress *object)
 		case OCLASS_ROLE:
 			{
 				appendStringInfo(&buffer, _("role %s"),
-								 GetUserNameFromId(object->objectId));
+								 GetUserNameFromId(object->objectId, false));
 				break;
 			}
 
@@ -2843,7 +2843,7 @@ getObjectDescription(const ObjectAddress *object)
 				ReleaseSysCache(tup);
 
 				if (OidIsValid(useid))
-					usename = GetUserNameFromId(useid);
+					usename = GetUserNameFromId(useid, false);
 				else
 					usename = "public";
 
@@ -2883,28 +2883,28 @@ getObjectDescription(const ObjectAddress *object)
 					case DEFACLOBJ_RELATION:
 						appendStringInfo(&buffer,
 										 _("default privileges on new relations belonging to role %s"),
-									  GetUserNameFromId(defacl->defaclrole));
+									  GetUserNameFromId(defacl->defaclrole, false));
 						break;
 					case DEFACLOBJ_SEQUENCE:
 						appendStringInfo(&buffer,
 										 _("default privileges on new sequences belonging to role %s"),
-									  GetUserNameFromId(defacl->defaclrole));
+									  GetUserNameFromId(defacl->defaclrole, false));
 						break;
 					case DEFACLOBJ_FUNCTION:
 						appendStringInfo(&buffer,
 										 _("default privileges on new functions belonging to role %s"),
-									  GetUserNameFromId(defacl->defaclrole));
+									  GetUserNameFromId(defacl->defaclrole, false));
 						break;
 					case DEFACLOBJ_TYPE:
 						appendStringInfo(&buffer,
 										 _("default privileges on new types belonging to role %s"),
-									  GetUserNameFromId(defacl->defaclrole));
+									  GetUserNameFromId(defacl->defaclrole, false));
 						break;
 					default:
 						/* shouldn't get here */
 						appendStringInfo(&buffer,
 								_("default privileges belonging to role %s"),
-									  GetUserNameFromId(defacl->defaclrole));
+									  GetUserNameFromId(defacl->defaclrole, false));
 						break;
 				}
 
@@ -4173,7 +4173,7 @@ getObjectIdentityParts(const ObjectAddress *object,
 			{
 				char	   *username;
 
-				username = GetUserNameFromId(object->objectId);
+				username = GetUserNameFromId(object->objectId, false);
 				if (objname)
 					*objname = list_make1(username);
 				appendStringInfoString(&buffer,
@@ -4254,7 +4254,7 @@ getObjectIdentityParts(const ObjectAddress *object,
 				ReleaseSysCache(tup);
 
 				if (OidIsValid(useid))
-					usename = GetUserNameFromId(useid);
+					usename = GetUserNameFromId(useid, false);
 				else
 					usename = "public";
 
@@ -4298,7 +4298,7 @@ getObjectIdentityParts(const ObjectAddress *object,
 
 				defacl = (Form_pg_default_acl) GETSTRUCT(tup);
 
-				username = GetUserNameFromId(defacl->defaclrole);
+				username = GetUserNameFromId(defacl->defaclrole, false);
 				appendStringInfo(&buffer,
 								 "for role %s",
 								 quote_identifier(username));
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
index 7701fc5..e7aecc9 100644
--- a/src/backend/utils/adt/acl.c
+++ b/src/backend/utils/adt/acl.c
@@ -4878,7 +4878,7 @@ check_is_member_of_role(Oid member, Oid role)
 		ereport(ERROR,
 				(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
 				 errmsg("must be member of role \"%s\"",
-						GetUserNameFromId(role))));
+						GetUserNameFromId(role, false))));
 }
 
 /*
diff --git a/src/backend/utils/adt/name.c b/src/backend/utils/adt/name.c
index b6c6e39..5826127 100644
--- a/src/backend/utils/adt/name.c
+++ b/src/backend/utils/adt/name.c
@@ -263,13 +263,13 @@ namestrcmp(Name name, const char *str)
 Datum
 current_user(PG_FUNCTION_ARGS)
 {
-	PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetUserId()))));
+	PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetUserId(), false))));
 }
 
 Datum
 session_user(PG_FUNCTION_ARGS)
 {
-	PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetSessionUserId()))));
+	PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetSessionUserId(), false))));
 }
 
 
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c
index a41f577..97dbc5e 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -1626,7 +1626,13 @@ regroleout(PG_FUNCTION_ARGS)
 		PG_RETURN_CSTRING(result);
 	}
 
-	result = GetUserNameFromId(roleoid);
+	result = GetUserNameFromId(roleoid, true);
+	if (!result)
+	{
+		/* If OID doesn't match any role, return it numerically */
+		result = (char *) palloc(NAMEDATALEN);
+		snprintf(result, NAMEDATALEN, "%u", roleoid);
+	}
 	PG_RETURN_CSTRING(result);
 }
 
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 1dc3153..b0d85af 100644
--- a/src/backend/utils/init/miscinit.c
+++ b/src/backend/utils/init/miscinit.c
@@ -648,23 +648,29 @@ SetCurrentRoleId(Oid roleid, bool is_superuser)
 
 
 /*
- * Get user name from user oid
+ * Get user name from user oid, returns NULL for nonexistent roleid if noerr
+ * is true.
  */
 char *
-GetUserNameFromId(Oid roleid)
+GetUserNameFromId(Oid roleid, bool noerr)
 {
 	HeapTuple	tuple;
 	char	   *result;
 
 	tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
 	if (!HeapTupleIsValid(tuple))
-		ereport(ERROR,
-				(errcode(ERRCODE_UNDEFINED_OBJECT),
-				 errmsg("invalid role OID: %u", roleid)));
-
-	result = pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname));
-
-	ReleaseSysCache(tuple);
+	{
+		if (!noerr)
+			ereport(ERROR,
+					(errcode(ERRCODE_UNDEFINED_OBJECT),
+					 errmsg("invalid role OID: %u", roleid)));
+		result = NULL;
+	}
+	else
+	{
+		result = pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname));
+		ReleaseSysCache(tuple);
+	}
 	return result;
 }
 
diff --git a/src/include/foreign/foreign.h b/src/include/foreign/foreign.h
index 9c737b4..c820e09 100644
--- a/src/include/foreign/foreign.h
+++ b/src/include/foreign/foreign.h
@@ -18,7 +18,7 @@
 
 /* Helper for obtaining username for user mapping */
 #define MappingUserName(userid) \
-	(OidIsValid(userid) ? GetUserNameFromId(userid) : "public")
+	(OidIsValid(userid) ? GetUserNameFromId(userid, false) : "public")
 
 
 /*
diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h
index eacfccb..56ae545 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -295,7 +295,7 @@ extern void InitStandaloneProcess(const char *argv0);
 
 extern void SetDatabasePath(const char *path);
 
-extern char *GetUserNameFromId(Oid roleid);
+extern char *GetUserNameFromId(Oid roleid, bool noerr);
 extern Oid	GetUserId(void);
 extern Oid	GetOuterUserId(void);
 extern Oid	GetSessionUserId(void);
-- 
1.8.3.1

