All,

I have attached a patch that addresses the current suggestions and
recommendations:

* Add 'get_all_role_attributes' SQL function - returns a text array
representation of the attributes from a value passed to it.

Example:

postgres=# SELECT rolname, get_all_role_attributes(rolattr) AS rolattr FROM
pg_authid;
 rolname  |                                            rolattr

----------+-----------------------------------------------------------------------------------------------
 postgres | {Superuser,Inherit,"Create Role","Create DB","Catalog
Update",Login,Replication,"Bypass RLS"}
(1 row)

* Refactor #define's from 'parsenodes.h' to 'acl.h'
* Added #define ROLE_ATTR_ALL to represent all currently available
attributes.
* Added genbki.pl substitution for  PGROLEATTRALL constant.

Please let me know what you think, all feedback is greatly appreciated.

Thanks,
Adam

-- 
Adam Brightwell - adam.brightw...@crunchydatasolutions.com
Database Engineer - www.crunchydatasolutions.com
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
new file mode 100644
index d30612c..93eb2e6
*** a/src/backend/catalog/aclchk.c
--- b/src/backend/catalog/aclchk.c
*************** aclcheck_error_type(AclResult aclerr, Oi
*** 3423,3448 ****
  }
  
  
- /* Check if given user has rolcatupdate privilege according to pg_authid */
- static bool
- has_rolcatupdate(Oid roleid)
- {
- 	bool		rolcatupdate;
- 	HeapTuple	tuple;
- 
- 	tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
- 	if (!HeapTupleIsValid(tuple))
- 		ereport(ERROR,
- 				(errcode(ERRCODE_UNDEFINED_OBJECT),
- 				 errmsg("role with OID %u does not exist", roleid)));
- 
- 	rolcatupdate = ((Form_pg_authid) GETSTRUCT(tuple))->rolcatupdate;
- 
- 	ReleaseSysCache(tuple);
- 
- 	return rolcatupdate;
- }
- 
  /*
   * Relay for the various pg_*_mask routines depending on object kind
   */
--- 3423,3428 ----
*************** pg_class_aclmask(Oid table_oid, Oid role
*** 3630,3636 ****
  	if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
  		IsSystemClass(table_oid, classForm) &&
  		classForm->relkind != RELKIND_VIEW &&
! 		!has_rolcatupdate(roleid) &&
  		!allowSystemTableMods)
  	{
  #ifdef ACLDEBUG
--- 3610,3616 ----
  	if ((mask & (ACL_INSERT | ACL_UPDATE | ACL_DELETE | ACL_TRUNCATE | ACL_USAGE)) &&
  		IsSystemClass(table_oid, classForm) &&
  		classForm->relkind != RELKIND_VIEW &&
! 		!role_has_attribute(roleid, ROLE_ATTR_CATUPDATE) &&
  		!allowSystemTableMods)
  	{
  #ifdef ACLDEBUG
*************** pg_extension_ownercheck(Oid ext_oid, Oid
*** 5051,5056 ****
--- 5031,5058 ----
  }
  
  /*
+  * Check whether the specified role has a specific role attribute.
+  */
+ bool
+ role_has_attribute(Oid roleid, RoleAttr attribute)
+ {
+ 	RoleAttr	attributes;
+ 	HeapTuple	tuple;
+ 
+ 	tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
+ 
+ 	if (!HeapTupleIsValid(tuple))
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_UNDEFINED_OBJECT),
+ 				 errmsg("role with OID %u does not exist", roleid)));
+ 
+ 	attributes = ((Form_pg_authid) GETSTRUCT(tuple))->rolattr;
+ 	ReleaseSysCache(tuple);
+ 
+ 	return ((attributes & attribute) > 0);
+ }
+ 
+ /*
   * Check whether specified role has CREATEROLE privilege (or is a superuser)
   *
   * Note: roles do not have owners per se; instead we use this test in
*************** pg_extension_ownercheck(Oid ext_oid, Oid
*** 5064,5102 ****
  bool
  has_createrole_privilege(Oid roleid)
  {
- 	bool		result = false;
- 	HeapTuple	utup;
- 
  	/* Superusers bypass all permission checking. */
  	if (superuser_arg(roleid))
  		return true;
  
! 	utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
! 	if (HeapTupleIsValid(utup))
! 	{
! 		result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreaterole;
! 		ReleaseSysCache(utup);
! 	}
! 	return result;
  }
  
  bool
  has_bypassrls_privilege(Oid roleid)
  {
- 	bool		result = false;
- 	HeapTuple	utup;
- 
  	/* Superusers bypass all permission checking. */
  	if (superuser_arg(roleid))
  		return true;
  
! 	utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
! 	if (HeapTupleIsValid(utup))
! 	{
! 		result = ((Form_pg_authid) GETSTRUCT(utup))->rolbypassrls;
! 		ReleaseSysCache(utup);
! 	}
! 	return result;
  }
  
  /*
--- 5066,5089 ----
  bool
  has_createrole_privilege(Oid roleid)
  {
  	/* Superusers bypass all permission checking. */
  	if (superuser_arg(roleid))
  		return true;
  
! 	return role_has_attribute(roleid, ROLE_ATTR_CREATEROLE);
  }
  
+ /*
+  * Check whether specified role has BYPASSRLS privilege.
+  */
  bool
  has_bypassrls_privilege(Oid roleid)
  {
  	/* Superusers bypass all permission checking. */
  	if (superuser_arg(roleid))
  		return true;
  
! 	return role_has_attribute(roleid, ROLE_ATTR_BYPASSRLS);
  }
  
  /*
diff --git a/src/backend/catalog/genbki.pl b/src/backend/catalog/genbki.pl
new file mode 100644
index ca89879..2929b66
*** a/src/backend/catalog/genbki.pl
--- b/src/backend/catalog/genbki.pl
*************** my $BOOTSTRAP_SUPERUSERID =
*** 90,95 ****
--- 90,97 ----
    find_defined_symbol('pg_authid.h', 'BOOTSTRAP_SUPERUSERID');
  my $PG_CATALOG_NAMESPACE =
    find_defined_symbol('pg_namespace.h', 'PG_CATALOG_NAMESPACE');
+ my $ROLE_ATTR_ALL =
+   find_defined_symbol('pg_authid.h', 'ROLE_ATTR_ALL');
  
  # Read all the input header files into internal data structures
  my $catalogs = Catalog::Catalogs(@input_files);
*************** foreach my $catname (@{ $catalogs->{name
*** 144,149 ****
--- 146,152 ----
  			# substitute constant values we acquired above
  			$row->{bki_values} =~ s/\bPGUID\b/$BOOTSTRAP_SUPERUSERID/g;
  			$row->{bki_values} =~ s/\bPGNSP\b/$PG_CATALOG_NAMESPACE/g;
+ 			$row->{bki_values} =~ s/\bPGROLATTRALL/$ROLE_ATTR_ALL/g;
  
  			# Save pg_type info for pg_attribute processing below
  			if ($catname eq 'pg_type')
diff --git a/src/backend/catalog/information_schema.sql b/src/backend/catalog/information_schema.sql
new file mode 100644
index a036c62..6904716
*** a/src/backend/catalog/information_schema.sql
--- b/src/backend/catalog/information_schema.sql
*************** CREATE VIEW user_mapping_options AS
*** 2884,2890 ****
             CAST((pg_options_to_table(um.umoptions)).option_name AS sql_identifier) AS option_name,
             CAST(CASE WHEN (umuser <> 0 AND authorization_identifier = current_user)
                         OR (umuser = 0 AND pg_has_role(srvowner, 'USAGE'))
!                        OR (SELECT rolsuper FROM pg_authid WHERE rolname = current_user) THEN (pg_options_to_table(um.umoptions)).option_value
                       ELSE NULL END AS character_data) AS option_value
      FROM _pg_user_mappings um;
  
--- 2884,2895 ----
             CAST((pg_options_to_table(um.umoptions)).option_name AS sql_identifier) AS option_name,
             CAST(CASE WHEN (umuser <> 0 AND authorization_identifier = current_user)
                         OR (umuser = 0 AND pg_has_role(srvowner, 'USAGE'))
!                        OR (
!                             SELECT has_role_attribute(pg_authid.oid, 'SUPERUSER') AS rolsuper
!                             FROM pg_authid
!                             WHERE rolname = current_user
!                           )
!                        THEN (pg_options_to_table(um.umoptions)).option_value
                       ELSE NULL END AS character_data) AS option_value
      FROM _pg_user_mappings um;
  
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
new file mode 100644
index 22b8cee..1fbcc27
*** a/src/backend/catalog/system_views.sql
--- b/src/backend/catalog/system_views.sql
***************
*** 9,25 ****
  CREATE VIEW pg_roles AS
      SELECT
          rolname,
!         rolsuper,
!         rolinherit,
!         rolcreaterole,
!         rolcreatedb,
!         rolcatupdate,
!         rolcanlogin,
!         rolreplication,
          rolconnlimit,
          '********'::text as rolpassword,
          rolvaliduntil,
-         rolbypassrls,
          setconfig as rolconfig,
          pg_authid.oid
      FROM pg_authid LEFT JOIN pg_db_role_setting s
--- 9,25 ----
  CREATE VIEW pg_roles AS
      SELECT
          rolname,
!         has_role_attribute(pg_authid.oid, 'SUPERUSER') AS rolsuper,
!         has_role_attribute(pg_authid.oid, 'INHERIT') AS rolinherit,
!         has_role_attribute(pg_authid.oid, 'CREATEROLE') AS rolcreaterole,
!         has_role_attribute(pg_authid.oid, 'CREATEDB') AS rolcreatedb,
!         has_role_attribute(pg_authid.oid, 'CATUPDATE') AS rolcatupdate,
!         has_role_attribute(pg_authid.oid, 'CANLOGIN') AS rolcanlogin,
!         has_role_attribute(pg_authid.oid, 'REPLICATION') AS rolreplication,
!         has_role_attribute(pg_authid.oid, 'BYPASSRLS') AS rolbypassrls,
          rolconnlimit,
          '********'::text as rolpassword,
          rolvaliduntil,
          setconfig as rolconfig,
          pg_authid.oid
      FROM pg_authid LEFT JOIN pg_db_role_setting s
*************** CREATE VIEW pg_shadow AS
*** 29,44 ****
      SELECT
          rolname AS usename,
          pg_authid.oid AS usesysid,
!         rolcreatedb AS usecreatedb,
!         rolsuper AS usesuper,
!         rolcatupdate AS usecatupd,
!         rolreplication AS userepl,
          rolpassword AS passwd,
          rolvaliduntil::abstime AS valuntil,
          setconfig AS useconfig
      FROM pg_authid LEFT JOIN pg_db_role_setting s
      ON (pg_authid.oid = setrole AND setdatabase = 0)
!     WHERE rolcanlogin;
  
  REVOKE ALL on pg_shadow FROM public;
  
--- 29,44 ----
      SELECT
          rolname AS usename,
          pg_authid.oid AS usesysid,
!         has_role_attribute(pg_authid.oid, 'CREATEDB') AS usecreatedb,
!         has_role_attribute(pg_authid.oid, 'SUPERUSER') AS usesuper,
!         has_role_attribute(pg_authid.oid, 'CATUPDATE') AS usecatupd,
!         has_role_attribute(pg_authid.oid, 'REPLICATION') AS userepl,
          rolpassword AS passwd,
          rolvaliduntil::abstime AS valuntil,
          setconfig AS useconfig
      FROM pg_authid LEFT JOIN pg_db_role_setting s
      ON (pg_authid.oid = setrole AND setdatabase = 0)
!     WHERE has_role_attribute(pg_authid.oid, 'CANLOGIN');
  
  REVOKE ALL on pg_shadow FROM public;
  
*************** CREATE VIEW pg_group AS
*** 48,54 ****
          oid AS grosysid,
          ARRAY(SELECT member FROM pg_auth_members WHERE roleid = oid) AS grolist
      FROM pg_authid
!     WHERE NOT rolcanlogin;
  
  CREATE VIEW pg_user AS
      SELECT
--- 48,54 ----
          oid AS grosysid,
          ARRAY(SELECT member FROM pg_auth_members WHERE roleid = oid) AS grolist
      FROM pg_authid
!     WHERE NOT has_role_attribute(pg_authid.oid, 'CANLOGIN');
  
  CREATE VIEW pg_user AS
      SELECT
diff --git a/src/backend/commands/dbcommands.c b/src/backend/commands/dbcommands.c
new file mode 100644
index 1a5244c..f46d69e
*** a/src/backend/commands/dbcommands.c
--- b/src/backend/commands/dbcommands.c
*************** get_db_info(const char *name, LOCKMODE l
*** 1806,1825 ****
  static bool
  have_createdb_privilege(void)
  {
- 	bool		result = false;
- 	HeapTuple	utup;
- 
  	/* Superusers can always do everything */
  	if (superuser())
  		return true;
  
! 	utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(GetUserId()));
! 	if (HeapTupleIsValid(utup))
! 	{
! 		result = ((Form_pg_authid) GETSTRUCT(utup))->rolcreatedb;
! 		ReleaseSysCache(utup);
! 	}
! 	return result;
  }
  
  /*
--- 1806,1816 ----
  static bool
  have_createdb_privilege(void)
  {
  	/* Superusers can always do everything */
  	if (superuser())
  		return true;
  
! 	return role_has_attribute(GetUserId(), ROLE_ATTR_CREATEDB);
  }
  
  /*
diff --git a/src/backend/commands/user.c b/src/backend/commands/user.c
new file mode 100644
index 1a73fd8..72c5dcc
*** a/src/backend/commands/user.c
--- b/src/backend/commands/user.c
*************** have_createrole_privilege(void)
*** 63,68 ****
--- 63,73 ----
  	return has_createrole_privilege(GetUserId());
  }
  
+ static RoleAttr
+ set_role_attribute(RoleAttr attributes, RoleAttr attribute)
+ {
+ 	return ((attributes & ~(0xFFFFFFFFFFFFFFFF)) | attribute);
+ }
  
  /*
   * CREATE ROLE
*************** CreateRole(CreateRoleStmt *stmt)
*** 81,93 ****
  	char	   *password = NULL;	/* user password */
  	bool		encrypt_password = Password_encryption; /* encrypt password? */
  	char		encrypted_password[MD5_PASSWD_LEN + 1];
! 	bool		issuper = false;	/* Make the user a superuser? */
! 	bool		inherit = true; /* Auto inherit privileges? */
  	bool		createrole = false;		/* Can this user create roles? */
  	bool		createdb = false;		/* Can the user create databases? */
  	bool		canlogin = false;		/* Can this user login? */
  	bool		isreplication = false;	/* Is this a replication role? */
  	bool		bypassrls = false;		/* Is this a row security enabled role? */
  	int			connlimit = -1; /* maximum connections allowed */
  	List	   *addroleto = NIL;	/* roles to make this a member of */
  	List	   *rolemembers = NIL;		/* roles to be members of this role */
--- 86,99 ----
  	char	   *password = NULL;	/* user password */
  	bool		encrypt_password = Password_encryption; /* encrypt password? */
  	char		encrypted_password[MD5_PASSWD_LEN + 1];
! 	bool		issuper = false;		/* Make the user a superuser? */
! 	bool		inherit = true;			/* Auto inherit privileges? */
  	bool		createrole = false;		/* Can this user create roles? */
  	bool		createdb = false;		/* Can the user create databases? */
  	bool		canlogin = false;		/* Can this user login? */
  	bool		isreplication = false;	/* Is this a replication role? */
  	bool		bypassrls = false;		/* Is this a row security enabled role? */
+ 	RoleAttr	attributes = ROLE_ATTR_NONE;	/* role attributes, initialized to none. */
  	int			connlimit = -1; /* maximum connections allowed */
  	List	   *addroleto = NIL;	/* roles to make this a member of */
  	List	   *rolemembers = NIL;		/* roles to be members of this role */
*************** CreateRole(CreateRoleStmt *stmt)
*** 249,254 ****
--- 255,262 ----
  
  	if (dpassword && dpassword->arg)
  		password = strVal(dpassword->arg);
+ 
+ 	/* Role Attributes */
  	if (dissuper)
  		issuper = intVal(dissuper->arg) != 0;
  	if (dinherit)
*************** CreateRole(CreateRoleStmt *stmt)
*** 261,266 ****
--- 269,277 ----
  		canlogin = intVal(dcanlogin->arg) != 0;
  	if (disreplication)
  		isreplication = intVal(disreplication->arg) != 0;
+ 	if (dbypassRLS)
+ 		bypassrls = intVal(dbypassRLS->arg) != 0;
+ 
  	if (dconnlimit)
  	{
  		connlimit = intVal(dconnlimit->arg);
*************** CreateRole(CreateRoleStmt *stmt)
*** 277,284 ****
  		adminmembers = (List *) dadminmembers->arg;
  	if (dvalidUntil)
  		validUntil = strVal(dvalidUntil->arg);
- 	if (dbypassRLS)
- 		bypassrls = intVal(dbypassRLS->arg) != 0;
  
  	/* Check some permissions first */
  	if (issuper)
--- 288,293 ----
*************** CreateRole(CreateRoleStmt *stmt)
*** 355,360 ****
--- 364,385 ----
  								validUntil_datum,
  								validUntil_null);
  
+ 	/* Set all role attributes */
+ 	if (issuper)
+ 		attributes |= ROLE_ATTR_SUPERUSER;
+ 	if (inherit)
+ 		attributes |= ROLE_ATTR_INHERIT;
+ 	if (createrole)
+ 		attributes |= ROLE_ATTR_CREATEROLE;
+ 	if (createdb)
+ 		attributes |= ROLE_ATTR_CREATEDB;
+ 	if (canlogin)
+ 		attributes |= ROLE_ATTR_CANLOGIN;
+ 	if (isreplication)
+ 		attributes |= ROLE_ATTR_REPLICATION;
+ 	if (bypassrls)
+ 		attributes |= ROLE_ATTR_BYPASSRLS;
+ 
  	/*
  	 * Build a tuple to insert
  	 */
*************** CreateRole(CreateRoleStmt *stmt)
*** 364,377 ****
  	new_record[Anum_pg_authid_rolname - 1] =
  		DirectFunctionCall1(namein, CStringGetDatum(stmt->role));
  
! 	new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper);
! 	new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit);
! 	new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole);
! 	new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb);
! 	/* superuser gets catupdate right by default */
! 	new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper);
! 	new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin);
! 	new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication);
  	new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
  
  	if (password)
--- 389,396 ----
  	new_record[Anum_pg_authid_rolname - 1] =
  		DirectFunctionCall1(namein, CStringGetDatum(stmt->role));
  
! 	new_record[Anum_pg_authid_rolattr - 1] = Int64GetDatum(attributes);
! 
  	new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
  
  	if (password)
*************** CreateRole(CreateRoleStmt *stmt)
*** 394,401 ****
  	new_record[Anum_pg_authid_rolvaliduntil - 1] = validUntil_datum;
  	new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
  
- 	new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(bypassrls);
- 
  	tuple = heap_form_tuple(pg_authid_dsc, new_record, new_record_nulls);
  
  	/*
--- 413,418 ----
*************** AlterRole(AlterRoleStmt *stmt)
*** 508,513 ****
--- 525,531 ----
  	DefElem    *dvalidUntil = NULL;
  	DefElem    *dbypassRLS = NULL;
  	Oid			roleid;
+ 	RoleAttr attributes;
  
  	/* Extract options from the statement node tree */
  	foreach(option, stmt->options)
*************** AlterRole(AlterRoleStmt *stmt)
*** 661,681 ****
  	 * To mess with a superuser you gotta be superuser; else you need
  	 * createrole, or just want to change your own password
  	 */
! 	if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper || issuper >= 0)
  	{
  		if (!superuser())
  			ereport(ERROR,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  					 errmsg("must be superuser to alter superusers")));
  	}
! 	else if (((Form_pg_authid) GETSTRUCT(tuple))->rolreplication || isreplication >= 0)
  	{
  		if (!superuser())
  			ereport(ERROR,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  					 errmsg("must be superuser to alter replication users")));
  	}
! 	else if (((Form_pg_authid) GETSTRUCT(tuple))->rolbypassrls || bypassrls >= 0)
  	{
  		if (!superuser())
  			ereport(ERROR,
--- 679,702 ----
  	 * To mess with a superuser you gotta be superuser; else you need
  	 * createrole, or just want to change your own password
  	 */
! 
! 	attributes = ((Form_pg_authid) GETSTRUCT(tuple))->rolattr;
! 
! 	if (((attributes & ROLE_ATTR_SUPERUSER) > 0) || issuper >= 0)
  	{
  		if (!superuser())
  			ereport(ERROR,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  					 errmsg("must be superuser to alter superusers")));
  	}
! 	else if (((attributes & ROLE_ATTR_REPLICATION) > 0) || isreplication >= 0)
  	{
  		if (!superuser())
  			ereport(ERROR,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  					 errmsg("must be superuser to alter replication users")));
  	}
! 	else if (((attributes & ROLE_ATTR_BYPASSRLS) > 0) || bypassrls >= 0)
  	{
  		if (!superuser())
  			ereport(ERROR,
*************** AlterRole(AlterRoleStmt *stmt)
*** 743,785 ****
  	 */
  	if (issuper >= 0)
  	{
! 		new_record[Anum_pg_authid_rolsuper - 1] = BoolGetDatum(issuper > 0);
! 		new_record_repl[Anum_pg_authid_rolsuper - 1] = true;
! 
! 		new_record[Anum_pg_authid_rolcatupdate - 1] = BoolGetDatum(issuper > 0);
! 		new_record_repl[Anum_pg_authid_rolcatupdate - 1] = true;
  	}
  
  	if (inherit >= 0)
  	{
! 		new_record[Anum_pg_authid_rolinherit - 1] = BoolGetDatum(inherit > 0);
! 		new_record_repl[Anum_pg_authid_rolinherit - 1] = true;
  	}
  
  	if (createrole >= 0)
  	{
! 		new_record[Anum_pg_authid_rolcreaterole - 1] = BoolGetDatum(createrole > 0);
! 		new_record_repl[Anum_pg_authid_rolcreaterole - 1] = true;
  	}
  
  	if (createdb >= 0)
  	{
! 		new_record[Anum_pg_authid_rolcreatedb - 1] = BoolGetDatum(createdb > 0);
! 		new_record_repl[Anum_pg_authid_rolcreatedb - 1] = true;
  	}
  
  	if (canlogin >= 0)
  	{
! 		new_record[Anum_pg_authid_rolcanlogin - 1] = BoolGetDatum(canlogin > 0);
! 		new_record_repl[Anum_pg_authid_rolcanlogin - 1] = true;
  	}
  
  	if (isreplication >= 0)
  	{
! 		new_record[Anum_pg_authid_rolreplication - 1] = BoolGetDatum(isreplication > 0);
! 		new_record_repl[Anum_pg_authid_rolreplication - 1] = true;
  	}
  
  	if (dconnlimit)
  	{
  		new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
--- 764,821 ----
  	 */
  	if (issuper >= 0)
  	{
! 		attributes = set_role_attribute(attributes,
! 							(issuper > 0) ? (ROLE_ATTR_SUPERUSER | ROLE_ATTR_CATUPDATE) :
! 							~(ROLE_ATTR_SUPERUSER | ROLE_ATTR_CATUPDATE));
! 		new_record_repl[Anum_pg_authid_rolattr - 1] = true;
  	}
  
  	if (inherit >= 0)
  	{
! 		attributes = set_role_attribute(attributes,
! 							(inherit > 0) ? ROLE_ATTR_INHERIT : ~(ROLE_ATTR_INHERIT));
! 		new_record_repl[Anum_pg_authid_rolattr - 1] = true;
  	}
  
  	if (createrole >= 0)
  	{
! 		attributes = set_role_attribute(attributes,
! 							(createrole > 0) ? ROLE_ATTR_CREATEROLE : ~(ROLE_ATTR_CREATEROLE));
! 		new_record_repl[Anum_pg_authid_rolattr - 1] = true;
  	}
  
  	if (createdb >= 0)
  	{
! 		attributes = set_role_attribute(attributes,
! 							(createdb > 0) ? ROLE_ATTR_CREATEDB : ~(ROLE_ATTR_CREATEDB));
! 		new_record_repl[Anum_pg_authid_rolattr - 1] = true;
  	}
  
  	if (canlogin >= 0)
  	{
! 		attributes = set_role_attribute(attributes,
! 							(canlogin > 0) ? ROLE_ATTR_CANLOGIN : ~(ROLE_ATTR_CANLOGIN));
! 		new_record_repl[Anum_pg_authid_rolattr - 1] = true;
  	}
  
  	if (isreplication >= 0)
  	{
! 		attributes = set_role_attribute(attributes,
! 							(isreplication > 0) ? ROLE_ATTR_REPLICATION : ~(ROLE_ATTR_REPLICATION));
! 		new_record_repl[Anum_pg_authid_rolattr - 1] = true;
  	}
  
+ 	if (bypassrls >= 0)
+ 	{
+ 		attributes = set_role_attribute(attributes,
+ 							(bypassrls > 0) ? ROLE_ATTR_BYPASSRLS : ~(ROLE_ATTR_BYPASSRLS));
+ 		new_record_repl[Anum_pg_authid_rolattr - 1] = true;
+ 	}
+ 
+ 	/* If any role attributes were set, then update. */
+ 	if (new_record_repl[Anum_pg_authid_rolattr - 1])
+ 		new_record[Anum_pg_authid_rolattr - 1] = Int64GetDatum(attributes);
+ 
  	if (dconnlimit)
  	{
  		new_record[Anum_pg_authid_rolconnlimit - 1] = Int32GetDatum(connlimit);
*************** AlterRole(AlterRoleStmt *stmt)
*** 815,825 ****
  	new_record_nulls[Anum_pg_authid_rolvaliduntil - 1] = validUntil_null;
  	new_record_repl[Anum_pg_authid_rolvaliduntil - 1] = true;
  
- 	if (bypassrls >= 0)
- 	{
- 		new_record[Anum_pg_authid_rolbypassrls - 1] = BoolGetDatum(bypassrls > 0);
- 		new_record_repl[Anum_pg_authid_rolbypassrls - 1] = true;
- 	}
  
  	new_tuple = heap_modify_tuple(tuple, pg_authid_dsc, new_record,
  								  new_record_nulls, new_record_repl);
--- 851,856 ----
*************** AlterRoleSet(AlterRoleSetStmt *stmt)
*** 867,872 ****
--- 898,904 ----
  	HeapTuple	roletuple;
  	Oid			databaseid = InvalidOid;
  	Oid			roleid = InvalidOid;
+ 	RoleAttr	attributes;
  
  	if (stmt->role)
  	{
*************** AlterRoleSet(AlterRoleSetStmt *stmt)
*** 889,895 ****
  		 * To mess with a superuser you gotta be superuser; else you need
  		 * createrole, or just want to change your own settings
  		 */
! 		if (((Form_pg_authid) GETSTRUCT(roletuple))->rolsuper)
  		{
  			if (!superuser())
  				ereport(ERROR,
--- 921,928 ----
  		 * To mess with a superuser you gotta be superuser; else you need
  		 * createrole, or just want to change your own settings
  		 */
! 		attributes = ((Form_pg_authid) GETSTRUCT(roletuple))->rolattr;
! 		if ((attributes & ROLE_ATTR_SUPERUSER) > 0)
  		{
  			if (!superuser())
  				ereport(ERROR,
*************** DropRole(DropRoleStmt *stmt)
*** 973,978 ****
--- 1006,1012 ----
  		char	   *detail_log;
  		SysScanDesc sscan;
  		Oid			roleid;
+ 		RoleAttr	attributes;
  
  		tuple = SearchSysCache1(AUTHNAME, PointerGetDatum(role));
  		if (!HeapTupleIsValid(tuple))
*************** DropRole(DropRoleStmt *stmt)
*** 1013,1020 ****
  		 * roles but not superuser roles.  This is mainly to avoid the
  		 * scenario where you accidentally drop the last superuser.
  		 */
! 		if (((Form_pg_authid) GETSTRUCT(tuple))->rolsuper &&
! 			!superuser())
  			ereport(ERROR,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  					 errmsg("must be superuser to drop superusers")));
--- 1047,1054 ----
  		 * roles but not superuser roles.  This is mainly to avoid the
  		 * scenario where you accidentally drop the last superuser.
  		 */
! 		attributes = ((Form_pg_authid) GETSTRUCT(tuple))->rolattr;
! 		if (((attributes & ROLE_ATTR_SUPERUSER) > 0) && !superuser())
  			ereport(ERROR,
  					(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
  					 errmsg("must be superuser to drop superusers")));
*************** RenameRole(const char *oldname, const ch
*** 1128,1133 ****
--- 1162,1168 ----
  	bool		repl_repl[Natts_pg_authid];
  	int			i;
  	Oid			roleid;
+ 	RoleAttr	attributes;
  
  	rel = heap_open(AuthIdRelationId, RowExclusiveLock);
  	dsc = RelationGetDescr(rel);
*************** RenameRole(const char *oldname, const ch
*** 1173,1179 ****
  	/*
  	 * createrole is enough privilege unless you want to mess with a superuser
  	 */
! 	if (((Form_pg_authid) GETSTRUCT(oldtuple))->rolsuper)
  	{
  		if (!superuser())
  			ereport(ERROR,
--- 1208,1215 ----
  	/*
  	 * createrole is enough privilege unless you want to mess with a superuser
  	 */
! 	attributes = ((Form_pg_authid) GETSTRUCT(oldtuple))->rolattr;
! 	if ((attributes & ROLE_ATTR_SUPERUSER) > 0)
  	{
  		if (!superuser())
  			ereport(ERROR,
diff --git a/src/backend/commands/variable.c b/src/backend/commands/variable.c
new file mode 100644
index 6ce8dae..a8a9f2e
*** a/src/backend/commands/variable.c
--- b/src/backend/commands/variable.c
*************** check_session_authorization(char **newva
*** 776,781 ****
--- 776,782 ----
  	Oid			roleid;
  	bool		is_superuser;
  	role_auth_extra *myextra;
+ 	RoleAttr	attributes;
  
  	/* Do nothing for the boot_val default of NULL */
  	if (*newval == NULL)
*************** check_session_authorization(char **newva
*** 800,806 ****
  	}
  
  	roleid = HeapTupleGetOid(roleTup);
! 	is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
  
  	ReleaseSysCache(roleTup);
  
--- 801,808 ----
  	}
  
  	roleid = HeapTupleGetOid(roleTup);
! 	attributes = ((Form_pg_authid) GETSTRUCT(roleTup))->rolattr;
! 	is_superuser = ((attributes & ROLE_ATTR_SUPERUSER) > 0);
  
  	ReleaseSysCache(roleTup);
  
*************** check_role(char **newval, void **extra,
*** 844,849 ****
--- 846,852 ----
  	Oid			roleid;
  	bool		is_superuser;
  	role_auth_extra *myextra;
+ 	RoleAttr	attributes;
  
  	if (strcmp(*newval, "none") == 0)
  	{
*************** check_role(char **newval, void **extra,
*** 872,878 ****
  		}
  
  		roleid = HeapTupleGetOid(roleTup);
! 		is_superuser = ((Form_pg_authid) GETSTRUCT(roleTup))->rolsuper;
  
  		ReleaseSysCache(roleTup);
  
--- 875,882 ----
  		}
  
  		roleid = HeapTupleGetOid(roleTup);
! 		attributes = ((Form_pg_authid) GETSTRUCT(roleTup))->rolattr;
! 		is_superuser = ((attributes & ROLE_ATTR_SUPERUSER) > 0);
  
  		ReleaseSysCache(roleTup);
  
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
new file mode 100644
index dc6eb2c..f6d86ac
*** a/src/backend/utils/adt/acl.c
--- b/src/backend/utils/adt/acl.c
*************** static Oid	convert_type_name(text *typen
*** 115,120 ****
--- 115,121 ----
  static AclMode convert_type_priv_string(text *priv_type_text);
  static AclMode convert_role_priv_string(text *priv_type_text);
  static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
+ static RoleAttr convert_role_attr_string(text *attr_type_text);
  
  static void RoleMembershipCacheCallback(Datum arg, int cacheid, uint32 hashvalue);
  
*************** aclitemin(PG_FUNCTION_ARGS)
*** 577,582 ****
--- 578,584 ----
  	PG_RETURN_ACLITEM_P(aip);
  }
  
+ 
  /*
   * aclitemout
   *		Allocates storage for, and fills in, a new null-delimited string
*************** pg_role_aclcheck(Oid role_oid, Oid rolei
*** 4602,4607 ****
--- 4604,4712 ----
  	return ACLCHECK_NO_PRIV;
  }
  
+ /*
+  * has_role_attribute_id
+  *		Check the named role attribute on a role by given role oid.
+  */
+ Datum
+ has_role_attribute_id(PG_FUNCTION_ARGS)
+ {
+ 	Oid			roleoid = PG_GETARG_OID(0);
+ 	text	   *attr_type_text = PG_GETARG_TEXT_P(1);
+ 	RoleAttr	attribute;
+ 
+ 	attribute = convert_role_attr_string(attr_type_text);
+ 
+ 	PG_RETURN_BOOL(role_has_attribute(roleoid, attribute));
+ }
+ 
+ /*
+  * get_all_role_attributes_attr
+  *		Convert a RoleAttr representation of role attributes into an array of
+  *		corresponding text values.
+  *
+  * The first and only argument is a RoleAttr (int64) representation of the
+  * role attributes.
+  */
+ Datum
+ get_all_role_attributes_rolattr(PG_FUNCTION_ARGS)
+ {
+ 	RoleAttr		attributes = PG_GETARG_INT64(0);
+ 	List		   *attribute_list = NIL;
+ 	ListCell	   *attribute;
+ 	Datum		   *temp_array;
+ 	ArrayType	   *result;
+ 	int				num_attributes;
+ 	int				i = 0;
+ 
+ 	/*
+ 	 * If no attributes are assigned, then there is no need to go through the
+ 	 * individual checks for which are assigned.  Therefore, we can short circuit
+ 	 * and return an empty array.
+ 	 */
+ 	if (attributes == ROLE_ATTR_NONE)
+ 		PG_RETURN_ARRAYTYPE_P(construct_empty_array(TEXTOID));
+ 
+ 	/* Determine which attributes are assigned. */
+ 	if ((attributes & ROLE_ATTR_SUPERUSER) > 0)
+ 		attribute_list = lappend(attribute_list, "Superuser");
+ 	if ((attributes & ROLE_ATTR_INHERIT) > 0)
+ 		attribute_list = lappend(attribute_list, "Inherit");
+ 	if ((attributes & ROLE_ATTR_CREATEROLE) > 0)
+ 		attribute_list = lappend(attribute_list, "Create Role");
+ 	if ((attributes & ROLE_ATTR_CREATEDB) > 0)
+ 		attribute_list = lappend(attribute_list, "Create DB");
+ 	if ((attributes & ROLE_ATTR_CATUPDATE) > 0)
+ 		attribute_list = lappend(attribute_list, "Catalog Update");
+ 	if ((attributes & ROLE_ATTR_CANLOGIN) > 0)
+ 		attribute_list = lappend(attribute_list, "Login");
+ 	if ((attributes & ROLE_ATTR_REPLICATION) > 0)
+ 		attribute_list = lappend(attribute_list, "Replication");
+ 	if ((attributes & ROLE_ATTR_BYPASSRLS) > 0)
+ 		attribute_list = lappend(attribute_list, "Bypass RLS");
+ 
+ 	/* Build and return result array */
+ 	num_attributes = list_length(attribute_list);
+ 	temp_array = (Datum *) palloc(num_attributes * sizeof(Datum));
+ 
+ 	foreach(attribute, attribute_list)
+ 		temp_array[i++] = CStringGetTextDatum(lfirst(attribute));
+ 
+ 	result = construct_array(temp_array, num_attributes, TEXTOID, -1, false, 'i');
+ 
+ 	PG_RETURN_ARRAYTYPE_P(result);
+ }
+ 
+ /*
+  * convert_role_attr_string
+  *		Convert text string to RoleAttr value.
+  */
+ static RoleAttr
+ convert_role_attr_string(text *attr_type_text)
+ {
+ 	char	   *attr_type = text_to_cstring(attr_type_text);
+ 
+ 	if (pg_strcasecmp(attr_type, "SUPERUSER") == 0)
+ 		return ROLE_ATTR_SUPERUSER;
+ 	else if (pg_strcasecmp(attr_type, "INHERIT") == 0)
+ 		return ROLE_ATTR_INHERIT;
+ 	else if (pg_strcasecmp(attr_type, "CREATEROLE") == 0)
+ 		return ROLE_ATTR_CREATEROLE;
+ 	else if (pg_strcasecmp(attr_type, "CREATEDB") == 0)
+ 		return ROLE_ATTR_CREATEDB;
+ 	else if (pg_strcasecmp(attr_type, "CATUPDATE") == 0)
+ 		return ROLE_ATTR_CATUPDATE;
+ 	else if (pg_strcasecmp(attr_type, "CANLOGIN") == 0)
+ 		return ROLE_ATTR_CANLOGIN;
+ 	else if (pg_strcasecmp(attr_type, "REPLICATION") == 0)
+ 		return ROLE_ATTR_REPLICATION;
+ 	else if (pg_strcasecmp(attr_type, "BYPASSRLS") == 0)
+ 		return ROLE_ATTR_BYPASSRLS;
+ 	else
+ 		ereport(ERROR,
+ 				(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
+ 				 errmsg("unrecognized role attribute: \"%s\"", attr_type)));
+ }
  
  /*
   * initialization function (called by InitPostgres)
*************** RoleMembershipCacheCallback(Datum arg, i
*** 4638,4653 ****
  static bool
  has_rolinherit(Oid roleid)
  {
! 	bool		result = false;
  	HeapTuple	utup;
  
  	utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
  	if (HeapTupleIsValid(utup))
  	{
! 		result = ((Form_pg_authid) GETSTRUCT(utup))->rolinherit;
  		ReleaseSysCache(utup);
  	}
! 	return result;
  }
  
  
--- 4743,4758 ----
  static bool
  has_rolinherit(Oid roleid)
  {
! 	RoleAttr	attributes;
  	HeapTuple	utup;
  
  	utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
  	if (HeapTupleIsValid(utup))
  	{
! 		attributes = ((Form_pg_authid) GETSTRUCT(utup))->rolattr;
  		ReleaseSysCache(utup);
  	}
! 	return ((attributes & ROLE_ATTR_INHERIT) > 0);
  }
  
  
diff --git a/src/backend/utils/init/miscinit.c b/src/backend/utils/init/miscinit.c
new file mode 100644
index 8fccb4c..9dd2dbc
*** a/src/backend/utils/init/miscinit.c
--- b/src/backend/utils/init/miscinit.c
***************
*** 40,45 ****
--- 40,46 ----
  #include "storage/pg_shmem.h"
  #include "storage/proc.h"
  #include "storage/procarray.h"
+ #include "utils/acl.h"
  #include "utils/builtins.h"
  #include "utils/guc.h"
  #include "utils/memutils.h"
*************** SetUserIdAndContext(Oid userid, bool sec
*** 334,349 ****
  bool
  has_rolreplication(Oid roleid)
  {
! 	bool		result = false;
  	HeapTuple	utup;
  
  	utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
  	if (HeapTupleIsValid(utup))
  	{
! 		result = ((Form_pg_authid) GETSTRUCT(utup))->rolreplication;
  		ReleaseSysCache(utup);
  	}
! 	return result;
  }
  
  /*
--- 335,350 ----
  bool
  has_rolreplication(Oid roleid)
  {
! 	RoleAttr	attributes;
  	HeapTuple	utup;
  
  	utup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
  	if (HeapTupleIsValid(utup))
  	{
! 		attributes = ((Form_pg_authid) GETSTRUCT(utup))->rolattr;
  		ReleaseSysCache(utup);
  	}
! 	return ((attributes & ROLE_ATTR_REPLICATION) > 0);
  }
  
  /*
*************** InitializeSessionUserId(const char *role
*** 375,381 ****
  	roleid = HeapTupleGetOid(roleTup);
  
  	AuthenticatedUserId = roleid;
! 	AuthenticatedUserIsSuperuser = rform->rolsuper;
  
  	/* This sets OuterUserId/CurrentUserId too */
  	SetSessionUserId(roleid, AuthenticatedUserIsSuperuser);
--- 376,382 ----
  	roleid = HeapTupleGetOid(roleTup);
  
  	AuthenticatedUserId = roleid;
! 	AuthenticatedUserIsSuperuser = ((rform->rolattr & ROLE_ATTR_SUPERUSER) > 0);
  
  	/* This sets OuterUserId/CurrentUserId too */
  	SetSessionUserId(roleid, AuthenticatedUserIsSuperuser);
*************** InitializeSessionUserId(const char *role
*** 394,400 ****
  		/*
  		 * Is role allowed to login at all?
  		 */
! 		if (!rform->rolcanlogin)
  			ereport(FATAL,
  					(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
  					 errmsg("role \"%s\" is not permitted to log in",
--- 395,401 ----
  		/*
  		 * Is role allowed to login at all?
  		 */
! 		if (!((rform->rolattr & ROLE_ATTR_CANLOGIN) > 0))
  			ereport(FATAL,
  					(errcode(ERRCODE_INVALID_AUTHORIZATION_SPECIFICATION),
  					 errmsg("role \"%s\" is not permitted to log in",
diff --git a/src/backend/utils/misc/superuser.c b/src/backend/utils/misc/superuser.c
new file mode 100644
index ff0f947..43febad
*** a/src/backend/utils/misc/superuser.c
--- b/src/backend/utils/misc/superuser.c
***************
*** 22,27 ****
--- 22,28 ----
  
  #include "access/htup_details.h"
  #include "catalog/pg_authid.h"
+ #include "utils/acl.h"
  #include "utils/inval.h"
  #include "utils/syscache.h"
  #include "miscadmin.h"
*************** superuser_arg(Oid roleid)
*** 58,63 ****
--- 59,65 ----
  {
  	bool		result;
  	HeapTuple	rtup;
+ 	RoleAttr	attributes;
  
  	/* Quick out for cache hit */
  	if (OidIsValid(last_roleid) && last_roleid == roleid)
*************** superuser_arg(Oid roleid)
*** 71,77 ****
  	rtup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
  	if (HeapTupleIsValid(rtup))
  	{
! 		result = ((Form_pg_authid) GETSTRUCT(rtup))->rolsuper;
  		ReleaseSysCache(rtup);
  	}
  	else
--- 73,80 ----
  	rtup = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
  	if (HeapTupleIsValid(rtup))
  	{
! 		attributes = ((Form_pg_authid) GETSTRUCT(rtup))->rolattr;
! 		result = ((attributes & ROLE_ATTR_SUPERUSER) > 0);
  		ReleaseSysCache(rtup);
  	}
  	else
diff --git a/src/include/catalog/pg_authid.h b/src/include/catalog/pg_authid.h
new file mode 100644
index 3b63d2b..ff8f035
*** a/src/include/catalog/pg_authid.h
--- b/src/include/catalog/pg_authid.h
***************
*** 22,27 ****
--- 22,28 ----
  #define PG_AUTHID_H
  
  #include "catalog/genbki.h"
+ #include "nodes/parsenodes.h"
  
  /*
   * The CATALOG definition has to refer to the type of rolvaliduntil as
***************
*** 45,60 ****
  CATALOG(pg_authid,1260) BKI_SHARED_RELATION BKI_ROWTYPE_OID(2842) BKI_SCHEMA_MACRO
  {
  	NameData	rolname;		/* name of role */
! 	bool		rolsuper;		/* read this field via superuser() only! */
! 	bool		rolinherit;		/* inherit privileges from other roles? */
! 	bool		rolcreaterole;	/* allowed to create more roles? */
! 	bool		rolcreatedb;	/* allowed to create databases? */
! 	bool		rolcatupdate;	/* allowed to alter catalogs manually? */
! 	bool		rolcanlogin;	/* allowed to log in as session user? */
! 	bool		rolreplication; /* role used for streaming replication */
! 	bool		rolbypassrls;	/* allowed to bypass row level security? */
  	int32		rolconnlimit;	/* max connections allowed (-1=no limit) */
- 
  	/* remaining fields may be null; use heap_getattr to read them! */
  	text		rolpassword;	/* password, if any */
  	timestamptz rolvaliduntil;	/* password expiration time, if any */
--- 46,53 ----
  CATALOG(pg_authid,1260) BKI_SHARED_RELATION BKI_ROWTYPE_OID(2842) BKI_SCHEMA_MACRO
  {
  	NameData	rolname;		/* name of role */
! 	int64		rolattr;		/* role attribute bitmask */
  	int32		rolconnlimit;	/* max connections allowed (-1=no limit) */
  	/* remaining fields may be null; use heap_getattr to read them! */
  	text		rolpassword;	/* password, if any */
  	timestamptz rolvaliduntil;	/* password expiration time, if any */
*************** typedef FormData_pg_authid *Form_pg_auth
*** 74,101 ****
   *		compiler constants for pg_authid
   * ----------------
   */
! #define Natts_pg_authid					12
  #define Anum_pg_authid_rolname			1
! #define Anum_pg_authid_rolsuper			2
! #define Anum_pg_authid_rolinherit		3
! #define Anum_pg_authid_rolcreaterole	4
! #define Anum_pg_authid_rolcreatedb		5
! #define Anum_pg_authid_rolcatupdate		6
! #define Anum_pg_authid_rolcanlogin		7
! #define Anum_pg_authid_rolreplication	8
! #define Anum_pg_authid_rolbypassrls		9
! #define Anum_pg_authid_rolconnlimit		10
! #define Anum_pg_authid_rolpassword		11
! #define Anum_pg_authid_rolvaliduntil	12
  
  /* ----------------
   *		initial contents of pg_authid
   *
   * The uppercase quantities will be replaced at initdb time with
   * user choices.
   * ----------------
   */
! DATA(insert OID = 10 ( "POSTGRES" t t t t t t t t -1 _null_ _null_));
  
  #define BOOTSTRAP_SUPERUSERID 10
  
--- 67,108 ----
   *		compiler constants for pg_authid
   * ----------------
   */
! #define Natts_pg_authid					5
  #define Anum_pg_authid_rolname			1
! #define Anum_pg_authid_rolattr			2
! #define Anum_pg_authid_rolconnlimit		3
! #define Anum_pg_authid_rolpassword		4
! #define Anum_pg_authid_rolvaliduntil	5
! 
! /* ----------------
!  * Role attributes are encoded so that we can OR them together in a bitmask.
!  * The present representation of RoleAttr (defined in acl.h) limits us to 64
!  * distinct rights.
!  * ----------------
!  */
! #define ROLE_ATTR_SUPERUSER		(1<<0)
! #define ROLE_ATTR_INHERIT		(1<<1)
! #define ROLE_ATTR_CREATEROLE	(1<<2)
! #define ROLE_ATTR_CREATEDB		(1<<3)
! #define ROLE_ATTR_CATUPDATE		(1<<4)
! #define ROLE_ATTR_CANLOGIN		(1<<5)
! #define ROLE_ATTR_REPLICATION	(1<<6)
! #define ROLE_ATTR_BYPASSRLS		(1<<7)
! #define N_ROLE_ATTRIBUTES		8		/* 1 plus the last 1<<x */
! #define ROLE_ATTR_NONE			0
! #define ROLE_ATTR_ALL			255		/* All currently available attributes. */
  
  /* ----------------
   *		initial contents of pg_authid
   *
   * The uppercase quantities will be replaced at initdb time with
   * user choices.
+  *
+  * PGROLATTRALL is substituted by genbki.pl to use the value defined by
+  * ROLE_ATTR_ALL.
   * ----------------
   */
! DATA(insert OID = 10 ( "POSTGRES" PGROLATTRALL -1 _null_ _null_));
  
  #define BOOTSTRAP_SUPERUSERID 10
  
diff --git a/src/include/catalog/pg_proc.h b/src/include/catalog/pg_proc.h
new file mode 100644
index 56399ac..84c6bee
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
*************** DESCR("current user privilege on any col
*** 2682,2687 ****
--- 2682,2693 ----
  DATA(insert OID = 3029 (  has_any_column_privilege	   PGNSP PGUID 12 10 0 0 0 f f f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ has_any_column_privilege_id _null_ _null_ _null_ ));
  DESCR("current user privilege on any column by rel oid");
  
+ DATA(insert OID = 6000 (  has_role_attribute		   PGNSP PGUID 12 10 0 0 0 f f f f t f s 2 0 16 "26 25" _null_ _null_ _null_ _null_ has_role_attribute_id _null_ _null_ _null_));
+ DESCR("user role attribute by user oid");
+ 
+ DATA(insert OID = 6001 (  get_all_role_attributes	   PGNSP PGUID 12 10 0 0 0 f f f f t f s 1 0 1009 "20" _null_ _null_ _null_ _null_ get_all_role_attributes_rolattr _null_ _null_ _null_));
+ DESCR("convert rolattr to string array");
+ 
  DATA(insert OID = 1928 (  pg_stat_get_numscans			PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 20 "26" _null_ _null_ _null_ _null_ pg_stat_get_numscans _null_ _null_ _null_ ));
  DESCR("statistics: number of scans done for table/index");
  DATA(insert OID = 1929 (  pg_stat_get_tuples_returned	PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 20 "26" _null_ _null_ _null_ _null_ pg_stat_get_tuples_returned _null_ _null_ _null_ ));
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
new file mode 100644
index 255415d..d59dcb4
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
*************** typedef uint32 AclMode;			/* a bitmask o
*** 78,83 ****
--- 78,101 ----
  /* Currently, SELECT ... FOR [KEY] UPDATE/SHARE requires UPDATE privileges */
  #define ACL_SELECT_FOR_UPDATE	ACL_UPDATE
  
+ /*
+  * Role attributes are encoded so that we can OR them together in a bitmask.
+  * The present representation of RoleAttr limits us to 64 distinct rights.
+  *
+  * Caution: changing these codes breaks stored RoleAttrs, hence forces initdb.
+  */
+ typedef uint64 RoleAttr;		/* a bitmask for role attribute bits */
+ 
+ #define ROLE_ATTR_SUPERUSER		(1<<0)
+ #define ROLE_ATTR_INHERIT		(1<<1)
+ #define ROLE_ATTR_CREATEROLE	(1<<2)
+ #define ROLE_ATTR_CREATEDB		(1<<3)
+ #define ROLE_ATTR_CATUPDATE		(1<<4)
+ #define ROLE_ATTR_CANLOGIN		(1<<5)
+ #define ROLE_ATTR_REPLICATION	(1<<6)
+ #define ROLE_ATTR_BYPASSRLS		(1<<7)
+ #define N_ROLE_ATTRIBUTES		8
+ #define ROLE_ATTR_NONE			0
  
  /*****************************************************************************
   *	Query Tree
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
new file mode 100644
index a8e3164..1460e94
*** a/src/include/utils/acl.h
--- b/src/include/utils/acl.h
*************** typedef enum AclObjectKind
*** 200,205 ****
--- 200,206 ----
  	MAX_ACL_KIND				/* MUST BE LAST */
  } AclObjectKind;
  
+ typedef uint64 RoleAttr;		/* a bitmask for role attribute bits */
  
  /*
   * routines used internally
*************** extern bool pg_event_trigger_ownercheck(
*** 328,332 ****
--- 329,334 ----
  extern bool pg_extension_ownercheck(Oid ext_oid, Oid roleid);
  extern bool has_createrole_privilege(Oid roleid);
  extern bool has_bypassrls_privilege(Oid roleid);
+ extern bool role_has_attribute(Oid roleid, RoleAttr capability);
  
  #endif   /* ACL_H */
diff --git a/src/include/utils/builtins.h b/src/include/utils/builtins.h
new file mode 100644
index 417fd17..7efee31
*** a/src/include/utils/builtins.h
--- b/src/include/utils/builtins.h
*************** extern Datum pg_has_role_id_name(PG_FUNC
*** 106,111 ****
--- 106,113 ----
  extern Datum pg_has_role_id_id(PG_FUNCTION_ARGS);
  extern Datum pg_has_role_name(PG_FUNCTION_ARGS);
  extern Datum pg_has_role_id(PG_FUNCTION_ARGS);
+ extern Datum has_role_attribute_id(PG_FUNCTION_ARGS);
+ extern Datum get_all_role_attributes_rolattr(PG_FUNCTION_ARGS);
  
  /* bool.c */
  extern Datum boolin(PG_FUNCTION_ARGS);
-- 
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