diff --git a/contrib/spi/insert_username.c b/contrib/spi/insert_username.c
index 875207881a8a8a8b10a52ca64dc66efa862c875c..3812525c4c083cb749314f5b15dc780e1c2026f2 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 0699438d6f6a7542413abe6f1521851907e71d23..e125986c2b31dc9823e3a13a6a340b4430eb2349 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/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml
index da1f25fe285e731d73793043f72eb8ec45ae0bcc..0cac9935d2d85a11c6c2b39d51a2fadc90528c73 100644
--- a/doc/src/sgml/datatype.sgml
+++ b/doc/src/sgml/datatype.sgml
@@ -4321,8 +4321,9 @@ SET xmloption TO { DOCUMENT | CONTENT };
     an object identifier.  There are also several alias types for
     <type>oid</>: <type>regproc</>, <type>regprocedure</>,
     <type>regoper</>, <type>regoperator</>, <type>regclass</>,
-    <type>regtype</>, <type>regconfig</>, and <type>regdictionary</>.
-    <xref linkend="datatype-oid-table"> shows an overview.
+    <type>regtype</>, <type>regrole</>, <type>regconfig</>, and
+    <type>regdictionary</>.  <xref linkend="datatype-oid-table"> shows
+    an overview.
    </para>
 
    <para>
@@ -4430,6 +4431,13 @@ SELECT * FROM pg_attribute
         <entry><literal>integer</></entry>
        </row>
 
+       <row>
+        <entry><type>regrole</></entry>
+        <entry><structname>pg_authid</></entry>
+        <entry>role name</entry>
+        <entry><literal>smithee</></entry>
+       </row>
+
        <row>
         <entry><type>regconfig</></entry>
         <entry><structname>pg_ts_config</></entry>
@@ -4448,7 +4456,8 @@ SELECT * FROM pg_attribute
     </table>
 
    <para>
-    All of the OID alias types accept schema-qualified names, and will
+    All of the OID alias types for objects grouped by namespace accept
+    schema-qualified names, and will
     display schema-qualified names on output if the object would not
     be found in the current search path without being qualified.
     The <type>regproc</> and <type>regoper</> alias types will only
@@ -4460,7 +4469,7 @@ SELECT * FROM pg_attribute
    </para>
 
    <para>
-    An additional property of the OID alias types is the creation of
+    An additional property of most of the OID alias types is the creation of
     dependencies.  If a
     constant of one of these types appears in a stored expression
     (such as a column default expression or view), it creates a dependency
@@ -4470,7 +4479,17 @@ SELECT * FROM pg_attribute
     understands that the default expression depends on the sequence
     <literal>my_seq</>; the system will not let the sequence be dropped
     without first removing the default expression.
+    <type>regrole</> is the only exception for the property. Constants of this
+    type are not allowed in such expressions.
+   </para>
+
+   <note>
+   <para>
+    The OID alias types do not completely follow transaction isolation
+    rules. The planner also treats them as simple constants, which may
+    result in sub-optimal planning.
    </para>
+   </note>
 
    <para>
     Another identifier type used by the system is <type>xid</>, or transaction
diff --git a/src/backend/bootstrap/bootstrap.c b/src/backend/bootstrap/bootstrap.c
index 6866d92238fbfe46b6c6d66053cfbb4f5ba3c0ca..66028d5877e07fa35f3b0a2bd8803c703f1b4caa 100644
--- a/src/backend/bootstrap/bootstrap.c
+++ b/src/backend/bootstrap/bootstrap.c
@@ -113,6 +113,8 @@ static const struct typinfo TypInfo[] = {
 	F_REGPROCIN, F_REGPROCOUT},
 	{"regtype", REGTYPEOID, 0, 4, true, 'i', 'p', InvalidOid,
 	F_REGTYPEIN, F_REGTYPEOUT},
+	{"regrole", REGROLEOID, 0, 4, true, 'i', 'p', InvalidOid,
+	F_REGROLEIN, F_REGROLEOUT},
 	{"text", TEXTOID, 0, -1, false, 'i', 'x', DEFAULT_COLLATION_OID,
 	F_TEXTIN, F_TEXTOUT},
 	{"oid", OIDOID, 0, 4, true, 'i', 'p', InvalidOid,
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
index 6271f8f5a036c0cf2174d241ecfd044153d1ace3..0ab57322f35e312f5228c9be4c1aacdd4747956b 100644
--- a/src/backend/catalog/dependency.c
+++ b/src/backend/catalog/dependency.c
@@ -1602,6 +1602,16 @@ find_expr_references_walker(Node *node,
 						add_object_address(OCLASS_TSDICT, objoid, 0,
 										   context->addrs);
 					break;
+
+				/*
+				 * Dependencies for regrole should be shared among all
+				 * databases, so explicitly inhibit to have dependencies.
+				 */
+				case REGROLEOID:
+					ereport(ERROR,
+							(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+							 errmsg("constant of the type \'regrole\' cannot be used here")));
+					break;
 			}
 		}
 		return false;
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
index 10f0396561bbccd450d42f98505db03a79a1ffc4..a1f8ada83375ea9fe85ceb74486e3e96cdd61f23 100644
--- a/src/backend/catalog/objectaddress.c
+++ b/src/backend/catalog/objectaddress.c
@@ -2818,7 +2818,7 @@ getObjectDescription(const ObjectAddress *object)
 		case OCLASS_ROLE:
 			{
 				appendStringInfo(&buffer, _("role %s"),
-								 GetUserNameFromId(object->objectId));
+								 GetUserNameFromId(object->objectId, false));
 				break;
 			}
 
@@ -2884,7 +2884,7 @@ getObjectDescription(const ObjectAddress *object)
 				ReleaseSysCache(tup);
 
 				if (OidIsValid(useid))
-					usename = GetUserNameFromId(useid);
+					usename = GetUserNameFromId(useid, false);
 				else
 					usename = "public";
 
@@ -2924,28 +2924,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;
 				}
 
@@ -4214,7 +4214,7 @@ getObjectIdentityParts(const ObjectAddress *object,
 			{
 				char	   *username;
 
-				username = GetUserNameFromId(object->objectId);
+				username = GetUserNameFromId(object->objectId, false);
 				if (objname)
 					*objname = list_make1(username);
 				appendStringInfoString(&buffer,
@@ -4295,7 +4295,7 @@ getObjectIdentityParts(const ObjectAddress *object,
 				ReleaseSysCache(tup);
 
 				if (OidIsValid(useid))
-					usename = GetUserNameFromId(useid);
+					usename = GetUserNameFromId(useid, false);
 				else
 					usename = "public";
 
@@ -4339,7 +4339,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 7701fc5ac07f4357ada4858be06e6d6b1eafc225..e7aecc95c97383a1470363c890aa50db477ffba2 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 b6c6e393358d4d7eeae3af4ae5fd066b691b719b..58261275614ec39e2a54d84ff8fcc867ca17c70a 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 11d663b295d1467a760e6c14d251a7c176bb9d3e..8b5672875c244a6befed2b084b2ed1778aba577c 100644
--- a/src/backend/utils/adt/regproc.c
+++ b/src/backend/utils/adt/regproc.c
@@ -40,6 +40,7 @@
 #include "utils/lsyscache.h"
 #include "utils/syscache.h"
 #include "utils/tqual.h"
+#include "utils/acl.h"
 
 static char *format_operator_internal(Oid operator_oid, bool force_qualify);
 static char *format_procedure_internal(Oid procedure_oid, bool force_qualify);
@@ -1553,6 +1554,109 @@ regdictionarysend(PG_FUNCTION_ARGS)
 	return oidsend(fcinfo);
 }
 
+/*
+ * regrolein	- converts "rolename" to role OID
+ *
+ * We also accept a numeric OID, for symmetry with the output routine.
+ *
+ * '-' signifies unknown (OID 0).  In all other cases, the input must
+ * match an existing pg_authid entry.
+ *
+ * This function is not needed in bootstrap mode, so we don't worry about
+ * making it work then.
+ */
+Datum
+regrolein(PG_FUNCTION_ARGS)
+{
+	char	   *role_name_or_oid = PG_GETARG_CSTRING(0);
+	Oid			result;
+
+	/* '-' ? */
+	if (strcmp(role_name_or_oid, "-") == 0)
+		PG_RETURN_OID(InvalidOid);
+
+	/* Numeric OID? */
+	if (role_name_or_oid[0] >= '0' &&
+		role_name_or_oid[0] <= '9' &&
+		strspn(role_name_or_oid, "0123456789") == strlen(role_name_or_oid))
+	{
+		result = DatumGetObjectId(DirectFunctionCall1(oidin,
+										 CStringGetDatum(role_name_or_oid)));
+		PG_RETURN_OID(result);
+	}
+
+	/* Normal case: see if the name matches any pg_authid entry. */
+	result = get_role_oid(role_name_or_oid, false);
+
+	PG_RETURN_OID(result);
+}
+
+/*
+ * to_regrole		- converts "rolename" to role OID
+ *
+ * If the name is not found, we return NULL.
+ */
+Datum
+to_regrole(PG_FUNCTION_ARGS)
+{
+	char	   *role_name = PG_GETARG_CSTRING(0);
+	Oid			result;
+
+	result = get_role_oid(role_name, true);
+
+	if (OidIsValid(result))
+		PG_RETURN_OID(result);
+	else
+		PG_RETURN_NULL();
+}
+
+/*
+ * regroleout		- converts role OID to "role_name"
+ */
+Datum
+regroleout(PG_FUNCTION_ARGS)
+{
+	Oid			roleoid = PG_GETARG_OID(0);
+	char	   *result;
+
+
+	if (roleoid == InvalidOid)
+	{
+		result = pstrdup("-");
+		PG_RETURN_CSTRING(result);
+	}
+
+	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);
+}
+
+/*
+ *		regrolerecv	- converts external binary format to regrole
+ */
+Datum
+regrolerecv(PG_FUNCTION_ARGS)
+{
+	/* Exactly the same as oidrecv, so share code */
+	return oidrecv(fcinfo);
+}
+
+/*
+ *		regrolesend	- converts regrole to binary format
+ */
+Datum
+regrolesend(PG_FUNCTION_ARGS)
+{
+	/* Exactly the same as oidsend, so share code */
+	return oidsend(fcinfo);
+}
+
+
 
 /*
  * text_regclass: convert text to regclass
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 4dd3f9fbce1679a38a4a15288cfe7a7e97ff7443..a28868c3130263d709e8631fd33eec602ae0590c 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -3619,6 +3619,7 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
 		case REGTYPEOID:
 		case REGCONFIGOID:
 		case REGDICTIONARYOID:
+		case REGROLEOID:
 			*scaledvalue = convert_numeric_to_scalar(value, valuetypid);
 			*scaledlobound = convert_numeric_to_scalar(lobound, boundstypid);
 			*scaledhibound = convert_numeric_to_scalar(hibound, boundstypid);
@@ -3724,6 +3725,7 @@ convert_numeric_to_scalar(Datum value, Oid typid)
 		case REGTYPEOID:
 		case REGCONFIGOID:
 		case REGDICTIONARYOID:
+		case REGROLEOID:
 			/* we can treat OIDs as integers... */
 			return (double) DatumGetObjectId(value);
 	}
diff --git a/src/backend/utils/cache/catcache.c b/src/backend/utils/cache/catcache.c
index 1af43c6de677e2cc6738389a62b36c27d921211d..9b7cc5eb76464b241a0475e66df35c8d938e1e7a 100644
--- a/src/backend/utils/cache/catcache.c
+++ b/src/backend/utils/cache/catcache.c
@@ -150,6 +150,7 @@ GetCCHashEqFuncs(Oid keytype, PGFunction *hashfunc, RegProcedure *eqfunc)
 		case REGTYPEOID:
 		case REGCONFIGOID:
 		case REGDICTIONARYOID:
+		case REGROLEOID:
 			*hashfunc = hashoid;
 
 			*eqfunc = F_OIDEQ;
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
index 1dc31535fd6e6d9cd0e7245bf07f34bdd32fef52..b0d85af14db6cf787a7164327e636c0acc6f3521 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/catalog/pg_cast.h b/src/include/catalog/pg_cast.h
index 259071ed2a97efd5f0037c8bbf3e72bdde67441e..4eba2ebbec581215e7e42392d35e7fb920abd3ff 100644
--- a/src/include/catalog/pg_cast.h
+++ b/src/include/catalog/pg_cast.h
@@ -210,6 +210,13 @@ DATA(insert ( 3769	 20 1288 a f ));
 DATA(insert ( 3769	 23    0 a b ));
 DATA(insert (	25 2205 1079 i f ));
 DATA(insert ( 1043 2205 1079 i f ));
+DATA(insert (	26 4096    0 i b ));
+DATA(insert ( 4096	 26    0 i b ));
+DATA(insert (	20 4096 1287 i f ));
+DATA(insert (	21 4096  313 i f ));
+DATA(insert (	23 4096    0 i b ));
+DATA(insert ( 4096	 20 1288 a f ));
+DATA(insert ( 4096	 23    0 a b ));
 
 /*
  * String category
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
index 76f9abf9fd183cbffd60633bcf54e53cbb2f9334..5452d10e8a8986618b212bd212803f17f42a3029 100644
--- a/src/include/catalog/pg_proc.h
+++ b/src/include/catalog/pg_proc.h
@@ -3481,6 +3481,13 @@ DESCR("convert type name to regtype");
 DATA(insert OID = 1079 (  regclass			PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2205 "25" _null_ _null_ _null_ _null_ _null_	text_regclass _null_ _null_ _null_ ));
 DESCR("convert text to regclass");
 
+DATA(insert OID = 4098 (  regrolein			PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 4096 "2275" _null_ _null_ _null_ _null_ _null_ regrolein _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 4092 (  regroleout		PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2275 "4096" _null_ _null_ _null_ _null_ _null_ regroleout _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 4093 (  to_regrole		PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 4096 "2275" _null_ _null_ _null_ _null_ _null_ to_regrole _null_ _null_ _null_ ));
+DESCR("convert role name to regrole");
+
 DATA(insert OID = 2246 ( fmgr_internal_validator PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ fmgr_internal_validator _null_ _null_ _null_ ));
 DESCR("(internal)");
 DATA(insert OID = 2247 ( fmgr_c_validator	PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ fmgr_c_validator _null_ _null_ _null_ ));
@@ -3876,6 +3883,11 @@ DATA(insert OID = 2454 (  regtyperecv		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1
 DESCR("I/O");
 DATA(insert OID = 2455 (  regtypesend		   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 17 "2206" _null_ _null_ _null_ _null_ _null_	regtypesend _null_ _null_ _null_ ));
 DESCR("I/O");
+
+DATA(insert OID = 4094 (  regrolerecv	  	   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 4096 "2281" _null_ _null_ _null_ _null_ _null_	regrolerecv _null_ _null_ _null_ ));
+DESCR("I/O");
+DATA(insert OID = 4095 (  regrolesend	       PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 17 "4096" _null_ _null_ _null_ _null_ _null_	regrolesend _null_ _null_ _null_ ));
+DESCR("I/O");
 DATA(insert OID = 2456 (  bit_recv			   PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 1560 "2281 26 23" _null_ _null_ _null_ _null_  _null_ bit_recv _null_ _null_ _null_ ));
 DESCR("I/O");
 DATA(insert OID = 2457 (  bit_send			   PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 17 "1560" _null_ _null_ _null_ _null_ _null_	bit_send _null_ _null_ _null_ ));
diff --git a/src/include/catalog/pg_type.h b/src/include/catalog/pg_type.h
index 0a900dd8afe87b139b6e1c5c057f1b70a10ae4d6..1430bc15b7447d2caecda5abe45f5b1c1494571f 100644
--- a/src/include/catalog/pg_type.h
+++ b/src/include/catalog/pg_type.h
@@ -564,12 +564,17 @@ DATA(insert OID = 2206 ( regtype	   PGNSP PGUID	4 t b N f t \054 0	 0 2211 regty
 DESCR("registered type");
 #define REGTYPEOID		2206
 
+DATA(insert OID = 4096 ( regrole       PGNSP PGUID	4 t b N f t \054 0	 0 4097 regrolein regroleout regrolerecv regrolesend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
+DESCR("registered role");
+#define REGROLEOID		4096
+
 DATA(insert OID = 2207 ( _regprocedure PGNSP PGUID -1 f b A f t \054 0 2202 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 2208 ( _regoper	   PGNSP PGUID -1 f b A f t \054 0 2203 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 2209 ( _regoperator  PGNSP PGUID -1 f b A f t \054 0 2204 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 2210 ( _regclass	   PGNSP PGUID -1 f b A f t \054 0 2205 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 DATA(insert OID = 2211 ( _regtype	   PGNSP PGUID -1 f b A f t \054 0 2206 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 #define REGTYPEARRAYOID 2211
+DATA(insert OID = 4097 ( _regrole      PGNSP PGUID -1 f b A f t \054 0 4096 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
 
 /* uuid */
 DATA(insert OID = 2950 ( uuid			PGNSP PGUID 16 f b U f t \054 0 0 2951 uuid_in uuid_out uuid_recv uuid_send - - - c p f 0 -1 0 0 _null_ _null_ _null_ ));
diff --git a/src/include/foreign/foreign.h b/src/include/foreign/foreign.h
index 9c737b4b3baaafb137b7d14d03aa0429bf35f993..c820e090023dc98e8c2da48d46e9a036db8d4e95 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 c38993973856b13513e050f45c176bdd4e67160a..71aa505e17da7c95d8f2adb873381589a14f8ec0 100644
--- a/src/include/miscadmin.h
+++ b/src/include/miscadmin.h
@@ -296,7 +296,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);
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
index 926421d9969fe4945a2e72f3b3453c56c1d31a5e..654ae1b305e36878d21cff526a6ea5a54ac3f925 100644
--- a/src/include/utils/builtins.h
+++ b/src/include/utils/builtins.h
@@ -630,6 +630,11 @@ extern Datum regtypeout(PG_FUNCTION_ARGS);
 extern Datum regtyperecv(PG_FUNCTION_ARGS);
 extern Datum regtypesend(PG_FUNCTION_ARGS);
 extern Datum to_regtype(PG_FUNCTION_ARGS);
+extern Datum regrolein(PG_FUNCTION_ARGS);
+extern Datum regroleout(PG_FUNCTION_ARGS);
+extern Datum regrolerecv(PG_FUNCTION_ARGS);
+extern Datum regrolesend(PG_FUNCTION_ARGS);
+extern Datum to_regrole(PG_FUNCTION_ARGS);
 extern Datum regconfigin(PG_FUNCTION_ARGS);
 extern Datum regconfigout(PG_FUNCTION_ARGS);
 extern Datum regconfigrecv(PG_FUNCTION_ARGS);
diff --git a/src/test/regress/expected/regproc.out b/src/test/regress/expected/regproc.out
index 33421292fd17dc1cef38423442b13142fe1af051..beda8ecabce7a0dbfbf25f9e944d0631d175b431 100644
--- a/src/test/regress/expected/regproc.out
+++ b/src/test/regress/expected/regproc.out
@@ -2,6 +2,7 @@
 -- regproc
 --
 /* If objects exist, return oids */
+CREATE ROLE regtestrole;
 -- without schemaname
 SELECT regoper('||/');
  regoper 
@@ -39,6 +40,12 @@ SELECT regtype('int4');
  integer
 (1 row)
 
+SELECT regrole('regtestrole');
+   regrole   
+-------------
+ regtestrole
+(1 row)
+
 SELECT to_regoper('||/');
  to_regoper 
 ------------
@@ -75,6 +82,12 @@ SELECT to_regtype('int4');
  integer
 (1 row)
 
+SELECT to_regrole('regtestrole');
+ to_regrole  
+-------------
+ regtestrole
+(1 row)
+
 -- with schemaname
 SELECT regoper('pg_catalog.||/');
  regoper 
@@ -143,10 +156,11 @@ SELECT to_regtype('pg_catalog.int4');
 (1 row)
 
 /* If objects don't exist, raise errors. */
+DROP ROLE regtestrole;
 -- without schemaname
 SELECT regoper('||//');
 ERROR:  operator does not exist: ||//
-LINE 3: SELECT regoper('||//');
+LINE 1: SELECT regoper('||//');
                        ^
 SELECT regoperator('++(int4,int4)');
 ERROR:  operator does not exist: ++(int4,int4)
@@ -168,6 +182,10 @@ SELECT regtype('int3');
 ERROR:  type "int3" does not exist
 LINE 1: SELECT regtype('int3');
                        ^
+SELECT regrole('regtestrole');
+ERROR:  role "regtestrole" does not exist
+LINE 1: SELECT regrole('regtestrole');
+                       ^
 -- with schemaname
 SELECT regoper('ng_catalog.||/');
 ERROR:  schema "ng_catalog" does not exist
@@ -231,6 +249,12 @@ SELECT to_regtype('int3');
  
 (1 row)
 
+SELECT to_regrole('regtestrole');
+ to_regrole 
+------------
+ 
+(1 row)
+
 -- with schemaname
 SELECT to_regoper('ng_catalog.||/');
  to_regoper 
diff --git a/src/test/regress/sql/regproc.sql b/src/test/regress/sql/regproc.sql
index cc90838bea247fc1bd25a7cdfe5166387de0185f..bc77c67cb8f8484667ddc9e8f6502d6aab04d07b 100644
--- a/src/test/regress/sql/regproc.sql
+++ b/src/test/regress/sql/regproc.sql
@@ -4,6 +4,7 @@
 
 /* If objects exist, return oids */
 
+CREATE ROLE regtestrole;
 -- without schemaname
 
 SELECT regoper('||/');
@@ -12,6 +13,7 @@ SELECT regproc('now');
 SELECT regprocedure('abs(numeric)');
 SELECT regclass('pg_class');
 SELECT regtype('int4');
+SELECT regrole('regtestrole');
 
 SELECT to_regoper('||/');
 SELECT to_regoperator('+(int4,int4)');
@@ -19,6 +21,7 @@ SELECT to_regproc('now');
 SELECT to_regprocedure('abs(numeric)');
 SELECT to_regclass('pg_class');
 SELECT to_regtype('int4');
+SELECT to_regrole('regtestrole');
 
 -- with schemaname
 
@@ -37,6 +40,8 @@ SELECT to_regtype('pg_catalog.int4');
 
 /* If objects don't exist, raise errors. */
 
+DROP ROLE regtestrole;
+
 -- without schemaname
 
 SELECT regoper('||//');
@@ -45,6 +50,7 @@ SELECT regproc('know');
 SELECT regprocedure('absinthe(numeric)');
 SELECT regclass('pg_classes');
 SELECT regtype('int3');
+SELECT regrole('regtestrole');
 
 -- with schemaname
 
@@ -65,6 +71,7 @@ SELECT to_regproc('know');
 SELECT to_regprocedure('absinthe(numeric)');
 SELECT to_regclass('pg_classes');
 SELECT to_regtype('int3');
+SELECT to_regrole('regtestrole');
 
 -- with schemaname