heap_close(pg_policy_rel, RowExclusiveLock);
 }
 
+/*
+ * RemoveRoleFromObjectPolicy -
+ *      remove a role from a policy by its OID.  If the role is not a member of
+ *      the policy then an error is raised.  False is returned to indicate that
+ *      the role could not be removed due to being the only role on the policy
+ *      and therefore the entire policy should be removed.
+ *
+ * Note that a warning will be thrown and true will be returned on a
+ * permission error, as the policy should not be removed in that case.
+ *
+ * roleid - the oid of the role to remove
+ * classid - should always be PolicyRelationId
+ * policy_id - the oid of the policy.
+ */
+bool
+RemoveRoleFromObjectPolicy(Oid roleid, Oid classid, Oid policy_id)
+{
+       Relation        pg_policy_rel;
+       SysScanDesc sscan;
+       ScanKeyData skey[1];
+       HeapTuple       tuple;
+       Oid                     relid;
+       Relation        rel;
+       ArrayType  *policy_roles;
+       int                     num_roles;
+       Datum           roles_datum;
+       bool            attr_isnull;
+       bool            noperm = true;
+
+       Assert(classid == PolicyRelationId);
+
+       pg_policy_rel = heap_open(PolicyRelationId, RowExclusiveLock);
+
+       /*
+        * Find the policy to update.
+        */
+       ScanKeyInit(&skey[0],
+                               ObjectIdAttributeNumber,
+                               BTEqualStrategyNumber, F_OIDEQ,
+                               ObjectIdGetDatum(policy_id));
+
+       sscan = systable_beginscan(pg_policy_rel, PolicyOidIndexId, true,
+                                                          NULL, 1, skey);
+
+       tuple = systable_getnext(sscan);
+
+       /* Raise an error if we don't find the policy. */
+       if (!HeapTupleIsValid(tuple))
+               elog(ERROR, "could not find tuple for policy %u", policy_id);
+
+       /*
+        * Open and exclusive-lock the relation the policy belongs to.
+        */
+       relid = ((Form_pg_policy) GETSTRUCT(tuple))->polrelid;
+
+       rel = relation_open(relid, AccessExclusiveLock);
+
+       if (rel->rd_rel->relkind != RELKIND_RELATION)
+               ereport(ERROR,
+                               (errcode(ERRCODE_WRONG_OBJECT_TYPE),
+                                errmsg("\"%s\" is not a table",
+                                               RelationGetRelationName(rel))));
+
+       if (!allowSystemTableMods && IsSystemRelation(rel))
+               ereport(ERROR,
+                               (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+                                errmsg("permission denied: \"%s\" is a system catalog",
+                                               RelationGetRelationName(rel))));
+
+       /* Get the current set of roles */
+       roles_datum = heap_getattr(tuple,
+                                                          Anum_pg_policy_polroles,
+                                                          RelationGetDescr(pg_policy_rel),
+                                                          &attr_isnull);
+
+       Assert(!attr_isnull);
+
+       policy_roles = DatumGetArrayTypePCopy(roles_datum);
+
+       /* We should be removing exactly one entry from the roles array */
+       num_roles = ARR_DIMS(policy_roles)[0] - 1;
+
+       Assert(num_roles >= 0);
+
+       /* Must own relation. */
+       if (pg_class_ownercheck(relid, GetUserId()))
+               noperm = false; /* user is allowed to modify this policy */
+       else
+               ereport(WARNING,
+                               (errcode(ERRCODE_WARNING_PRIVILEGE_NOT_REVOKED),
+                                errmsg("role \"%s\" could not be removed from policy \"%s\" on \"%s\"",
+                                               GetUserNameFromId(roleid, false),
+                                               NameStr(((Form_pg_policy) GETSTRUCT(tuple))->polname),
+                                               RelationGetRelationName(rel))));
+
+       /*
+        * If multiple roles exist on this policy, then remove the one we were
+        * asked to and leave the rest.
+        */
+       if (!noperm && num_roles > 0)
+       {
+               int                     i, j;
+               Oid                *roles = (Oid *) ARR_DATA_PTR(policy_roles);
+               Datum      *role_oids;
+               char       *qual_value;
+               Node       *qual_expr;
+               List       *qual_parse_rtable = NIL;
+               char       *with_check_value;
+               Node       *with_check_qual;
+               List       *with_check_parse_rtable = NIL;
+               Datum           values[Natts_pg_policy];
+               bool            isnull[Natts_pg_policy];
+               bool            replaces[Natts_pg_policy];
+               Datum           value_datum;
+               ArrayType  *role_ids;
+               HeapTuple       new_tuple;
+               ObjectAddress target;
+               ObjectAddress myself;
+
+               /* zero-clear */
+               memset(values, 0, sizeof(values));
+               memset(replaces, 0, sizeof(replaces));
+               memset(isnull, 0, sizeof(isnull));
+
+               /*
+                * All of the dependencies will be removed from the policy and then
+                * re-added.  In order to get them correct, we need to extract out
+                * the expressions in the policy and construct a parsestate just
+                * enough to build the range table(s) to then pass to
+                * recordDependencyOnExpr().
+                */
+
+               /* Get policy qual, to update dependencies */
+               value_datum = heap_getattr(tuple, Anum_pg_policy_polqual,
+                                                                  RelationGetDescr(pg_policy_rel), &attr_isnull);
+               if (!attr_isnull)
+               {
+                       ParseState *qual_pstate;
+
+                       /* parsestate is built just to build the range table */
+                       qual_pstate = make_parsestate(NULL);
+
+                       qual_value = TextDatumGetCString(value_datum);
+                       qual_expr = stringToNode(qual_value);
+
+                       /* Add this rel to the parsestate's rangetable, for dependencies */
+                       addRangeTableEntryForRelation(qual_pstate, rel, NULL, false, false);
+
+                       qual_parse_rtable = qual_pstate->p_rtable;
+                       free_parsestate(qual_pstate);
+               }
+               else
+                       qual_expr = NULL;
+
+               /* Get WITH CHECK qual, to update dependencies */
+               value_datum = heap_getattr(tuple, Anum_pg_policy_polwithcheck,
+                                                                  RelationGetDescr(pg_policy_rel), &attr_isnull);
+               if (!attr_isnull)
+               {
+                       ParseState *with_check_pstate;
+
+                       /* parsestate is built just to build the range table */
+                       with_check_pstate = make_parsestate(NULL);
+
+                       with_check_value = TextDatumGetCString(value_datum);
+                       with_check_qual = stringToNode(with_check_value);
+
+                       /* Add this rel to the parsestate's rangetable, for dependencies */
+                       addRangeTableEntryForRelation(with_check_pstate, rel, NULL, false,
+                                                                                 false);
+
+                       with_check_parse_rtable = with_check_pstate->p_rtable;
+                       free_parsestate(with_check_pstate);
+               }
+               else
+                       with_check_qual = NULL;
+
+               /* Rebuild the roles array to then update the pg_policy tuple with */
+               role_oids = (Datum *) palloc(num_roles * sizeof(Datum));
+               for (i = 0, j = 0; i < ARR_DIMS(policy_roles)[0]; i++)
+                       /* Copy over all of the roles which are not the one being removed */
+                       if (roles[i] != roleid)
+                               role_oids[j++] = ObjectIdGetDatum(roles[i]);
+
+               /* We should have only removed the one role */
+               Assert(j == num_roles);
+
+               /* This is the array for the new tuple */
+               role_ids = construct_array(role_oids, num_roles, OIDOID,
+                                                                  sizeof(Oid), true, 'i');
+
+               replaces[Anum_pg_policy_polroles - 1] = true;
+               values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids);
+
+               new_tuple = heap_modify_tuple(tuple,
+                                                                         RelationGetDescr(pg_policy_rel),
+                                                                         values, isnull, replaces);
+               simple_heap_update(pg_policy_rel, &new_tuple->t_self, new_tuple);
+
+               /* Update Catalog Indexes */
+               CatalogUpdateIndexes(pg_policy_rel, new_tuple);
+
+               /* Remove all old dependencies. */
+               deleteDependencyRecordsFor(PolicyRelationId, policy_id, false);
+
+               /* Record the new set of dependencies */
+               target.classId = RelationRelationId;
+               target.objectId = relid;
+               target.objectSubId = 0;
+
+               myself.classId = PolicyRelationId;
+               myself.objectId = policy_id;
+               myself.objectSubId = 0;
+
+               recordDependencyOn(&myself, &target, DEPENDENCY_AUTO);
+
+               if (qual_expr)
+                       recordDependencyOnExpr(&myself, qual_expr, qual_parse_rtable,
+                                                                  DEPENDENCY_NORMAL);
+
+               if (with_check_qual)
+                       recordDependencyOnExpr(&myself, with_check_qual,
+                                                                  with_check_parse_rtable,
+                                                                  DEPENDENCY_NORMAL);
+
+               /* Remove all the old shared dependencies (roles) */
+               deleteSharedDependencyRecordsFor(PolicyRelationId, policy_id, 0);
+
+               /* Record the new shared dependencies (roles) */
+               target.classId = AuthIdRelationId;
+               target.objectSubId = 0;
+               for (i = 0; i < num_roles; i++)
+               {
+                       target.objectId = DatumGetObjectId(role_oids[i]);
+                       /* no need for dependency on the public role */
+                       if (target.objectId != ACL_ID_PUBLIC)
+                               recordSharedDependencyOn(&myself, &target,
+                                                                                SHARED_DEPENDENCY_POLICY);
+               }
+
+               InvokeObjectPostAlterHook(PolicyRelationId, policy_id, 0);
+
+               heap_freetuple(new_tuple);
+
+               /* Invalidate Relation Cache */
+               CacheInvalidateRelcache(rel);
+       }
+
+       /* Clean up. */
+       systable_endscan(sscan);
+       relation_close(rel, AccessExclusiveLock);
+       heap_close(pg_policy_rel, RowExclusiveLock);
+
+       return(noperm || num_roles > 0);
+}
+
 /*
  * CreatePolicy -
  *      handles the execution of the CREATE POLICY command.