|
|
|
@ -22,7 +22,7 @@
|
|
|
|
|
#include "catalog/indexing.h"
|
|
|
|
|
#include "catalog/namespace.h"
|
|
|
|
|
#include "catalog/objectaccess.h"
|
|
|
|
|
#include "catalog/pg_rowsecurity.h"
|
|
|
|
|
#include "catalog/pg_policy.h"
|
|
|
|
|
#include "catalog/pg_type.h"
|
|
|
|
|
#include "commands/policy.h"
|
|
|
|
|
#include "miscadmin.h"
|
|
|
|
@ -46,8 +46,8 @@
|
|
|
|
|
|
|
|
|
|
static void RangeVarCallbackForPolicy(const RangeVar *rv,
|
|
|
|
|
Oid relid, Oid oldrelid, void *arg);
|
|
|
|
|
static char parse_row_security_command(const char *cmd_name);
|
|
|
|
|
static ArrayType* rls_role_list_to_array(List *roles);
|
|
|
|
|
static char parse_policy_command(const char *cmd_name);
|
|
|
|
|
static ArrayType* policy_role_list_to_array(List *roles);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Callback to RangeVarGetRelidExtended().
|
|
|
|
@ -95,7 +95,7 @@ RangeVarCallbackForPolicy(const RangeVar *rv, Oid relid, Oid oldrelid,
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* parse_row_security_command -
|
|
|
|
|
* parse_policy_command -
|
|
|
|
|
* helper function to convert full command strings to their char
|
|
|
|
|
* representation.
|
|
|
|
|
*
|
|
|
|
@ -104,7 +104,7 @@ RangeVarCallbackForPolicy(const RangeVar *rv, Oid relid, Oid oldrelid,
|
|
|
|
|
*
|
|
|
|
|
*/
|
|
|
|
|
static char
|
|
|
|
|
parse_row_security_command(const char *cmd_name)
|
|
|
|
|
parse_policy_command(const char *cmd_name)
|
|
|
|
|
{
|
|
|
|
|
char cmd;
|
|
|
|
|
|
|
|
|
@ -128,7 +128,7 @@ parse_row_security_command(const char *cmd_name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* rls_role_list_to_array
|
|
|
|
|
* policy_role_list_to_array
|
|
|
|
|
* helper function to convert a list of role names in to an array of
|
|
|
|
|
* role ids.
|
|
|
|
|
*
|
|
|
|
@ -138,7 +138,7 @@ parse_row_security_command(const char *cmd_name)
|
|
|
|
|
* roles - the list of role names to convert.
|
|
|
|
|
*/
|
|
|
|
|
static ArrayType *
|
|
|
|
|
rls_role_list_to_array(List *roles)
|
|
|
|
|
policy_role_list_to_array(List *roles)
|
|
|
|
|
{
|
|
|
|
|
ArrayType *role_ids;
|
|
|
|
|
Datum *temp_array;
|
|
|
|
@ -190,7 +190,7 @@ rls_role_list_to_array(List *roles)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Load row-security policy from the catalog, and keep it in
|
|
|
|
|
* Load row security policy from the catalog, and keep it in
|
|
|
|
|
* the relation cache.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
@ -204,14 +204,14 @@ RelationBuildRowSecurity(Relation relation)
|
|
|
|
|
MemoryContext rscxt = NULL;
|
|
|
|
|
RowSecurityDesc *rsdesc = NULL;
|
|
|
|
|
|
|
|
|
|
catalog = heap_open(RowSecurityRelationId, AccessShareLock);
|
|
|
|
|
catalog = heap_open(PolicyRelationId, AccessShareLock);
|
|
|
|
|
|
|
|
|
|
ScanKeyInit(&skey,
|
|
|
|
|
Anum_pg_rowsecurity_rsecrelid,
|
|
|
|
|
Anum_pg_policy_polrelid,
|
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
|
ObjectIdGetDatum(RelationGetRelid(relation)));
|
|
|
|
|
|
|
|
|
|
sscan = systable_beginscan(catalog, RowSecurityRelidPolnameIndexId, true,
|
|
|
|
|
sscan = systable_beginscan(catalog, PolicyPolrelidPolnameIndexId, true,
|
|
|
|
|
NULL, 1, &skey);
|
|
|
|
|
PG_TRY();
|
|
|
|
|
{
|
|
|
|
@ -221,7 +221,7 @@ RelationBuildRowSecurity(Relation relation)
|
|
|
|
|
* default-deny policy is created.
|
|
|
|
|
*/
|
|
|
|
|
rscxt = AllocSetContextCreate(CacheMemoryContext,
|
|
|
|
|
"Row-security descriptor",
|
|
|
|
|
"row security descriptor",
|
|
|
|
|
ALLOCSET_SMALL_MINSIZE,
|
|
|
|
|
ALLOCSET_SMALL_INITSIZE,
|
|
|
|
|
ALLOCSET_SMALL_MAXSIZE);
|
|
|
|
@ -229,7 +229,7 @@ RelationBuildRowSecurity(Relation relation)
|
|
|
|
|
rsdesc->rscxt = rscxt;
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Loop through the row-level security entries for this relation, if
|
|
|
|
|
* Loop through the row level security policies for this relation, if
|
|
|
|
|
* any.
|
|
|
|
|
*/
|
|
|
|
|
while (HeapTupleIsValid(tuple = systable_getnext(sscan)))
|
|
|
|
@ -249,7 +249,7 @@ RelationBuildRowSecurity(Relation relation)
|
|
|
|
|
oldcxt = MemoryContextSwitchTo(rscxt);
|
|
|
|
|
|
|
|
|
|
/* Get policy command */
|
|
|
|
|
value_datum = heap_getattr(tuple, Anum_pg_rowsecurity_rseccmd,
|
|
|
|
|
value_datum = heap_getattr(tuple, Anum_pg_policy_polcmd,
|
|
|
|
|
RelationGetDescr(catalog), &isnull);
|
|
|
|
|
if (isnull)
|
|
|
|
|
cmd_value = 0;
|
|
|
|
@ -257,19 +257,19 @@ RelationBuildRowSecurity(Relation relation)
|
|
|
|
|
cmd_value = DatumGetChar(value_datum);
|
|
|
|
|
|
|
|
|
|
/* Get policy name */
|
|
|
|
|
value_datum = heap_getattr(tuple, Anum_pg_rowsecurity_rsecpolname,
|
|
|
|
|
value_datum = heap_getattr(tuple, Anum_pg_policy_polname,
|
|
|
|
|
RelationGetDescr(catalog), &isnull);
|
|
|
|
|
Assert(!isnull);
|
|
|
|
|
policy_name_value = DatumGetCString(value_datum);
|
|
|
|
|
|
|
|
|
|
/* Get policy roles */
|
|
|
|
|
value_datum = heap_getattr(tuple, Anum_pg_rowsecurity_rsecroles,
|
|
|
|
|
value_datum = heap_getattr(tuple, Anum_pg_policy_polroles,
|
|
|
|
|
RelationGetDescr(catalog), &isnull);
|
|
|
|
|
Assert(!isnull);
|
|
|
|
|
roles = DatumGetArrayTypeP(value_datum);
|
|
|
|
|
|
|
|
|
|
/* Get policy qual */
|
|
|
|
|
value_datum = heap_getattr(tuple, Anum_pg_rowsecurity_rsecqual,
|
|
|
|
|
value_datum = heap_getattr(tuple, Anum_pg_policy_polqual,
|
|
|
|
|
RelationGetDescr(catalog), &isnull);
|
|
|
|
|
if (!isnull)
|
|
|
|
|
{
|
|
|
|
@ -280,7 +280,7 @@ RelationBuildRowSecurity(Relation relation)
|
|
|
|
|
qual_expr = NULL;
|
|
|
|
|
|
|
|
|
|
/* Get WITH CHECK qual */
|
|
|
|
|
value_datum = heap_getattr(tuple, Anum_pg_rowsecurity_rsecwithcheck,
|
|
|
|
|
value_datum = heap_getattr(tuple, Anum_pg_policy_polwithcheck,
|
|
|
|
|
RelationGetDescr(catalog), &isnull);
|
|
|
|
|
|
|
|
|
|
if (!isnull)
|
|
|
|
@ -295,7 +295,7 @@ RelationBuildRowSecurity(Relation relation)
|
|
|
|
|
|
|
|
|
|
policy = palloc0(sizeof(RowSecurityPolicy));
|
|
|
|
|
policy->policy_name = policy_name_value;
|
|
|
|
|
policy->rsecid = policy_id;
|
|
|
|
|
policy->policy_id = policy_id;
|
|
|
|
|
policy->cmd = cmd_value;
|
|
|
|
|
policy->roles = roles;
|
|
|
|
|
policy->qual = copyObject(qual_expr);
|
|
|
|
@ -317,7 +317,7 @@ RelationBuildRowSecurity(Relation relation)
|
|
|
|
|
/*
|
|
|
|
|
* Check if no policies were added
|
|
|
|
|
*
|
|
|
|
|
* If no policies exist in pg_rowsecurity for this relation, then we
|
|
|
|
|
* If no policies exist in pg_policy for this relation, then we
|
|
|
|
|
* need to create a single default-deny policy. We use InvalidOid for
|
|
|
|
|
* the Oid to indicate that this is the default-deny policy (we may
|
|
|
|
|
* decide to ignore the default policy if an extension adds policies).
|
|
|
|
@ -333,7 +333,7 @@ RelationBuildRowSecurity(Relation relation)
|
|
|
|
|
|
|
|
|
|
policy = palloc0(sizeof(RowSecurityPolicy));
|
|
|
|
|
policy->policy_name = pstrdup("default-deny policy");
|
|
|
|
|
policy->rsecid = InvalidOid;
|
|
|
|
|
policy->policy_id = InvalidOid;
|
|
|
|
|
policy->cmd = '\0';
|
|
|
|
|
policy->roles = construct_array(&role, 1, OIDOID, sizeof(Oid), true,
|
|
|
|
|
'i');
|
|
|
|
@ -364,22 +364,22 @@ RelationBuildRowSecurity(Relation relation)
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* RemovePolicyById -
|
|
|
|
|
* remove a row-security policy by its OID. If a policy does not exist with
|
|
|
|
|
* the provided oid, then an error is raised.
|
|
|
|
|
* remove a policy by its OID. If a policy does not exist with the provided
|
|
|
|
|
* oid, then an error is raised.
|
|
|
|
|
*
|
|
|
|
|
* policy_id - the oid of the row-security policy.
|
|
|
|
|
* policy_id - the oid of the policy.
|
|
|
|
|
*/
|
|
|
|
|
void
|
|
|
|
|
RemovePolicyById(Oid policy_id)
|
|
|
|
|
{
|
|
|
|
|
Relation pg_rowsecurity_rel;
|
|
|
|
|
Relation pg_policy_rel;
|
|
|
|
|
SysScanDesc sscan;
|
|
|
|
|
ScanKeyData skey[1];
|
|
|
|
|
HeapTuple tuple;
|
|
|
|
|
Oid relid;
|
|
|
|
|
Relation rel;
|
|
|
|
|
|
|
|
|
|
pg_rowsecurity_rel = heap_open(RowSecurityRelationId, RowExclusiveLock);
|
|
|
|
|
pg_policy_rel = heap_open(PolicyRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Find the policy to delete.
|
|
|
|
@ -389,19 +389,19 @@ RemovePolicyById(Oid policy_id)
|
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
|
ObjectIdGetDatum(policy_id));
|
|
|
|
|
|
|
|
|
|
sscan = systable_beginscan(pg_rowsecurity_rel, RowSecurityOidIndexId, true,
|
|
|
|
|
sscan = systable_beginscan(pg_policy_rel, PolicyOidIndexId, true,
|
|
|
|
|
NULL, 1, skey);
|
|
|
|
|
|
|
|
|
|
tuple = systable_getnext(sscan);
|
|
|
|
|
|
|
|
|
|
/* If the policy exists, then remove it, otherwise raise an error. */
|
|
|
|
|
if (!HeapTupleIsValid(tuple))
|
|
|
|
|
elog(ERROR, "could not find tuple for row-security %u", policy_id);
|
|
|
|
|
elog(ERROR, "could not find tuple for policy %u", policy_id);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Open and exclusive-lock the relation the policy belong to.
|
|
|
|
|
*/
|
|
|
|
|
relid = ((Form_pg_rowsecurity) GETSTRUCT(tuple))->rsecrelid;
|
|
|
|
|
relid = ((Form_pg_policy) GETSTRUCT(tuple))->polrelid;
|
|
|
|
|
|
|
|
|
|
rel = heap_open(relid, AccessExclusiveLock);
|
|
|
|
|
if (rel->rd_rel->relkind != RELKIND_RELATION)
|
|
|
|
@ -416,7 +416,7 @@ RemovePolicyById(Oid policy_id)
|
|
|
|
|
errmsg("permission denied: \"%s\" is a system catalog",
|
|
|
|
|
RelationGetRelationName(rel))));
|
|
|
|
|
|
|
|
|
|
simple_heap_delete(pg_rowsecurity_rel, &tuple->t_self);
|
|
|
|
|
simple_heap_delete(pg_policy_rel, &tuple->t_self);
|
|
|
|
|
|
|
|
|
|
systable_endscan(sscan);
|
|
|
|
|
heap_close(rel, AccessExclusiveLock);
|
|
|
|
@ -424,9 +424,8 @@ RemovePolicyById(Oid policy_id)
|
|
|
|
|
/*
|
|
|
|
|
* Note that, unlike some of the other flags in pg_class, relrowsecurity
|
|
|
|
|
* is not just an indication of if policies exist. When relrowsecurity
|
|
|
|
|
* is set (which can be done directly by the user or indirectly by creating
|
|
|
|
|
* a policy on the table), then all access to the relation must be through
|
|
|
|
|
* a policy. If no policy is defined for the relation then a default-deny
|
|
|
|
|
* is set by a user, then all access to the relation must be through a
|
|
|
|
|
* policy. If no policy is defined for the relation then a default-deny
|
|
|
|
|
* policy is created and all records are filtered (except for queries from
|
|
|
|
|
* the owner).
|
|
|
|
|
*/
|
|
|
|
@ -434,7 +433,7 @@ RemovePolicyById(Oid policy_id)
|
|
|
|
|
CacheInvalidateRelcache(rel);
|
|
|
|
|
|
|
|
|
|
/* Clean up */
|
|
|
|
|
heap_close(pg_rowsecurity_rel, RowExclusiveLock);
|
|
|
|
|
heap_close(pg_policy_rel, RowExclusiveLock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -446,11 +445,11 @@ RemovePolicyById(Oid policy_id)
|
|
|
|
|
Oid
|
|
|
|
|
CreatePolicy(CreatePolicyStmt *stmt)
|
|
|
|
|
{
|
|
|
|
|
Relation pg_rowsecurity_rel;
|
|
|
|
|
Oid rowsec_id;
|
|
|
|
|
Relation pg_policy_rel;
|
|
|
|
|
Oid policy_id;
|
|
|
|
|
Relation target_table;
|
|
|
|
|
Oid table_id;
|
|
|
|
|
char rseccmd;
|
|
|
|
|
char polcmd;
|
|
|
|
|
ArrayType *role_ids;
|
|
|
|
|
ParseState *qual_pstate;
|
|
|
|
|
ParseState *with_check_pstate;
|
|
|
|
@ -459,19 +458,19 @@ CreatePolicy(CreatePolicyStmt *stmt)
|
|
|
|
|
Node *with_check_qual;
|
|
|
|
|
ScanKeyData skey[2];
|
|
|
|
|
SysScanDesc sscan;
|
|
|
|
|
HeapTuple rsec_tuple;
|
|
|
|
|
Datum values[Natts_pg_rowsecurity];
|
|
|
|
|
bool isnull[Natts_pg_rowsecurity];
|
|
|
|
|
HeapTuple policy_tuple;
|
|
|
|
|
Datum values[Natts_pg_policy];
|
|
|
|
|
bool isnull[Natts_pg_policy];
|
|
|
|
|
ObjectAddress target;
|
|
|
|
|
ObjectAddress myself;
|
|
|
|
|
|
|
|
|
|
/* Parse command */
|
|
|
|
|
rseccmd = parse_row_security_command(stmt->cmd);
|
|
|
|
|
polcmd = parse_policy_command(stmt->cmd);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the command is SELECT or DELETE then WITH CHECK should be NULL.
|
|
|
|
|
*/
|
|
|
|
|
if ((rseccmd == ACL_SELECT_CHR || rseccmd == ACL_DELETE_CHR)
|
|
|
|
|
if ((polcmd == ACL_SELECT_CHR || polcmd == ACL_DELETE_CHR)
|
|
|
|
|
&& stmt->with_check != NULL)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
@ -481,14 +480,14 @@ CreatePolicy(CreatePolicyStmt *stmt)
|
|
|
|
|
* If the command is INSERT then WITH CHECK should be the only expression
|
|
|
|
|
* provided.
|
|
|
|
|
*/
|
|
|
|
|
if (rseccmd == ACL_INSERT_CHR && stmt->qual != NULL)
|
|
|
|
|
if (polcmd == ACL_INSERT_CHR && stmt->qual != NULL)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
|
errmsg("only WITH CHECK expression allowed for INSERT")));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* Collect role ids */
|
|
|
|
|
role_ids = rls_role_list_to_array(stmt->roles);
|
|
|
|
|
role_ids = policy_role_list_to_array(stmt->roles);
|
|
|
|
|
|
|
|
|
|
/* Parse the supplied clause */
|
|
|
|
|
qual_pstate = make_parsestate(NULL);
|
|
|
|
@ -527,74 +526,74 @@ CreatePolicy(CreatePolicyStmt *stmt)
|
|
|
|
|
EXPR_KIND_WHERE,
|
|
|
|
|
"POLICY");
|
|
|
|
|
|
|
|
|
|
/* Open pg_rowsecurity catalog */
|
|
|
|
|
pg_rowsecurity_rel = heap_open(RowSecurityRelationId, RowExclusiveLock);
|
|
|
|
|
/* Open pg_policy catalog */
|
|
|
|
|
pg_policy_rel = heap_open(PolicyRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
|
|
/* Set key - row security relation id. */
|
|
|
|
|
/* Set key - policy's relation id. */
|
|
|
|
|
ScanKeyInit(&skey[0],
|
|
|
|
|
Anum_pg_rowsecurity_rsecrelid,
|
|
|
|
|
Anum_pg_policy_polrelid,
|
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
|
ObjectIdGetDatum(table_id));
|
|
|
|
|
|
|
|
|
|
/* Set key - row security policy name. */
|
|
|
|
|
/* Set key - policy's name. */
|
|
|
|
|
ScanKeyInit(&skey[1],
|
|
|
|
|
Anum_pg_rowsecurity_rsecpolname,
|
|
|
|
|
Anum_pg_policy_polname,
|
|
|
|
|
BTEqualStrategyNumber, F_NAMEEQ,
|
|
|
|
|
CStringGetDatum(stmt->policy_name));
|
|
|
|
|
|
|
|
|
|
sscan = systable_beginscan(pg_rowsecurity_rel,
|
|
|
|
|
RowSecurityRelidPolnameIndexId, true, NULL, 2,
|
|
|
|
|
sscan = systable_beginscan(pg_policy_rel,
|
|
|
|
|
PolicyPolrelidPolnameIndexId, true, NULL, 2,
|
|
|
|
|
skey);
|
|
|
|
|
|
|
|
|
|
rsec_tuple = systable_getnext(sscan);
|
|
|
|
|
policy_tuple = systable_getnext(sscan);
|
|
|
|
|
|
|
|
|
|
/* Complain if the policy name already exists for the table */
|
|
|
|
|
if (HeapTupleIsValid(rsec_tuple))
|
|
|
|
|
if (HeapTupleIsValid(policy_tuple))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
|
errmsg("policy \"%s\" for relation \"%s\" already exists",
|
|
|
|
|
stmt->policy_name, RelationGetRelationName(target_table))));
|
|
|
|
|
|
|
|
|
|
values[Anum_pg_rowsecurity_rsecrelid - 1] = ObjectIdGetDatum(table_id);
|
|
|
|
|
values[Anum_pg_rowsecurity_rsecpolname - 1]
|
|
|
|
|
values[Anum_pg_policy_polrelid - 1] = ObjectIdGetDatum(table_id);
|
|
|
|
|
values[Anum_pg_policy_polname - 1]
|
|
|
|
|
= DirectFunctionCall1(namein, CStringGetDatum(stmt->policy_name));
|
|
|
|
|
|
|
|
|
|
if (rseccmd)
|
|
|
|
|
values[Anum_pg_rowsecurity_rseccmd - 1] = CharGetDatum(rseccmd);
|
|
|
|
|
if (polcmd)
|
|
|
|
|
values[Anum_pg_policy_polcmd - 1] = CharGetDatum(polcmd);
|
|
|
|
|
else
|
|
|
|
|
isnull[Anum_pg_rowsecurity_rseccmd - 1] = true;
|
|
|
|
|
isnull[Anum_pg_policy_polcmd - 1] = true;
|
|
|
|
|
|
|
|
|
|
values[Anum_pg_rowsecurity_rsecroles - 1] = PointerGetDatum(role_ids);
|
|
|
|
|
values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids);
|
|
|
|
|
|
|
|
|
|
/* Add qual if present. */
|
|
|
|
|
if (qual)
|
|
|
|
|
values[Anum_pg_rowsecurity_rsecqual - 1]
|
|
|
|
|
values[Anum_pg_policy_polqual - 1]
|
|
|
|
|
= CStringGetTextDatum(nodeToString(qual));
|
|
|
|
|
else
|
|
|
|
|
isnull[Anum_pg_rowsecurity_rsecqual - 1] = true;
|
|
|
|
|
isnull[Anum_pg_policy_polqual - 1] = true;
|
|
|
|
|
|
|
|
|
|
/* Add WITH CHECK qual if present */
|
|
|
|
|
if (with_check_qual)
|
|
|
|
|
values[Anum_pg_rowsecurity_rsecwithcheck - 1]
|
|
|
|
|
values[Anum_pg_policy_polwithcheck - 1]
|
|
|
|
|
= CStringGetTextDatum(nodeToString(with_check_qual));
|
|
|
|
|
else
|
|
|
|
|
isnull[Anum_pg_rowsecurity_rsecwithcheck - 1] = true;
|
|
|
|
|
isnull[Anum_pg_policy_polwithcheck - 1] = true;
|
|
|
|
|
|
|
|
|
|
rsec_tuple = heap_form_tuple(RelationGetDescr(pg_rowsecurity_rel), values,
|
|
|
|
|
isnull);
|
|
|
|
|
policy_tuple = heap_form_tuple(RelationGetDescr(pg_policy_rel), values,
|
|
|
|
|
isnull);
|
|
|
|
|
|
|
|
|
|
rowsec_id = simple_heap_insert(pg_rowsecurity_rel, rsec_tuple);
|
|
|
|
|
policy_id = simple_heap_insert(pg_policy_rel, policy_tuple);
|
|
|
|
|
|
|
|
|
|
/* Update Indexes */
|
|
|
|
|
CatalogUpdateIndexes(pg_rowsecurity_rel, rsec_tuple);
|
|
|
|
|
CatalogUpdateIndexes(pg_policy_rel, policy_tuple);
|
|
|
|
|
|
|
|
|
|
/* Record Dependencies */
|
|
|
|
|
target.classId = RelationRelationId;
|
|
|
|
|
target.objectId = table_id;
|
|
|
|
|
target.objectSubId = 0;
|
|
|
|
|
|
|
|
|
|
myself.classId = RowSecurityRelationId;
|
|
|
|
|
myself.objectId = rowsec_id;
|
|
|
|
|
myself.classId = PolicyRelationId;
|
|
|
|
|
myself.objectId = policy_id;
|
|
|
|
|
myself.objectSubId = 0;
|
|
|
|
|
|
|
|
|
|
recordDependencyOn(&myself, &target, DEPENDENCY_AUTO);
|
|
|
|
@ -609,14 +608,14 @@ CreatePolicy(CreatePolicyStmt *stmt)
|
|
|
|
|
CacheInvalidateRelcache(target_table);
|
|
|
|
|
|
|
|
|
|
/* Clean up. */
|
|
|
|
|
heap_freetuple(rsec_tuple);
|
|
|
|
|
heap_freetuple(policy_tuple);
|
|
|
|
|
free_parsestate(qual_pstate);
|
|
|
|
|
free_parsestate(with_check_pstate);
|
|
|
|
|
systable_endscan(sscan);
|
|
|
|
|
relation_close(target_table, NoLock);
|
|
|
|
|
heap_close(pg_rowsecurity_rel, RowExclusiveLock);
|
|
|
|
|
heap_close(pg_policy_rel, RowExclusiveLock);
|
|
|
|
|
|
|
|
|
|
return rowsec_id;
|
|
|
|
|
return policy_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -628,8 +627,8 @@ CreatePolicy(CreatePolicyStmt *stmt)
|
|
|
|
|
Oid
|
|
|
|
|
AlterPolicy(AlterPolicyStmt *stmt)
|
|
|
|
|
{
|
|
|
|
|
Relation pg_rowsecurity_rel;
|
|
|
|
|
Oid rowsec_id;
|
|
|
|
|
Relation pg_policy_rel;
|
|
|
|
|
Oid policy_id;
|
|
|
|
|
Relation target_table;
|
|
|
|
|
Oid table_id;
|
|
|
|
|
ArrayType *role_ids = NULL;
|
|
|
|
@ -639,20 +638,20 @@ AlterPolicy(AlterPolicyStmt *stmt)
|
|
|
|
|
Node *with_check_qual = NULL;
|
|
|
|
|
ScanKeyData skey[2];
|
|
|
|
|
SysScanDesc sscan;
|
|
|
|
|
HeapTuple rsec_tuple;
|
|
|
|
|
HeapTuple policy_tuple;
|
|
|
|
|
HeapTuple new_tuple;
|
|
|
|
|
Datum values[Natts_pg_rowsecurity];
|
|
|
|
|
bool isnull[Natts_pg_rowsecurity];
|
|
|
|
|
bool replaces[Natts_pg_rowsecurity];
|
|
|
|
|
Datum values[Natts_pg_policy];
|
|
|
|
|
bool isnull[Natts_pg_policy];
|
|
|
|
|
bool replaces[Natts_pg_policy];
|
|
|
|
|
ObjectAddress target;
|
|
|
|
|
ObjectAddress myself;
|
|
|
|
|
Datum cmd_datum;
|
|
|
|
|
char rseccmd;
|
|
|
|
|
bool rseccmd_isnull;
|
|
|
|
|
char polcmd;
|
|
|
|
|
bool polcmd_isnull;
|
|
|
|
|
|
|
|
|
|
/* Parse role_ids */
|
|
|
|
|
if (stmt->roles != NULL)
|
|
|
|
|
role_ids = rls_role_list_to_array(stmt->roles);
|
|
|
|
|
role_ids = policy_role_list_to_array(stmt->roles);
|
|
|
|
|
|
|
|
|
|
/* Get id of table. Also handles permissions checks. */
|
|
|
|
|
table_id = RangeVarGetRelidExtended(stmt->table, AccessExclusiveLock,
|
|
|
|
@ -662,7 +661,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
|
|
|
|
|
|
|
|
|
|
target_table = relation_open(table_id, NoLock);
|
|
|
|
|
|
|
|
|
|
/* Parse the row-security clause */
|
|
|
|
|
/* Parse the using policy clause */
|
|
|
|
|
if (stmt->qual)
|
|
|
|
|
{
|
|
|
|
|
RangeTblEntry *rte;
|
|
|
|
@ -675,13 +674,13 @@ AlterPolicy(AlterPolicyStmt *stmt)
|
|
|
|
|
|
|
|
|
|
qual = transformWhereClause(qual_pstate, copyObject(stmt->qual),
|
|
|
|
|
EXPR_KIND_WHERE,
|
|
|
|
|
"ROW SECURITY");
|
|
|
|
|
"POLICY");
|
|
|
|
|
|
|
|
|
|
qual_parse_rtable = qual_pstate->p_rtable;
|
|
|
|
|
free_parsestate(qual_pstate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Parse the with-check row-security clause */
|
|
|
|
|
/* Parse the with-check policy clause */
|
|
|
|
|
if (stmt->with_check)
|
|
|
|
|
{
|
|
|
|
|
RangeTblEntry *rte;
|
|
|
|
@ -695,7 +694,7 @@ AlterPolicy(AlterPolicyStmt *stmt)
|
|
|
|
|
with_check_qual = transformWhereClause(with_check_pstate,
|
|
|
|
|
copyObject(stmt->with_check),
|
|
|
|
|
EXPR_KIND_WHERE,
|
|
|
|
|
"ROW SECURITY");
|
|
|
|
|
"POLICY");
|
|
|
|
|
|
|
|
|
|
with_check_parse_rtable = with_check_pstate->p_rtable;
|
|
|
|
|
free_parsestate(with_check_pstate);
|
|
|
|
@ -707,28 +706,28 @@ AlterPolicy(AlterPolicyStmt *stmt)
|
|
|
|
|
memset(isnull, 0, sizeof(isnull));
|
|
|
|
|
|
|
|
|
|
/* Find policy to update. */
|
|
|
|
|
pg_rowsecurity_rel = heap_open(RowSecurityRelationId, RowExclusiveLock);
|
|
|
|
|
pg_policy_rel = heap_open(PolicyRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
|
|
/* Set key - row security relation id. */
|
|
|
|
|
/* Set key - policy's relation id. */
|
|
|
|
|
ScanKeyInit(&skey[0],
|
|
|
|
|
Anum_pg_rowsecurity_rsecrelid,
|
|
|
|
|
Anum_pg_policy_polrelid,
|
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
|
ObjectIdGetDatum(table_id));
|
|
|
|
|
|
|
|
|
|
/* Set key - row security policy name. */
|
|
|
|
|
/* Set key - policy's name. */
|
|
|
|
|
ScanKeyInit(&skey[1],
|
|
|
|
|
Anum_pg_rowsecurity_rsecpolname,
|
|
|
|
|
Anum_pg_policy_polname,
|
|
|
|
|
BTEqualStrategyNumber, F_NAMEEQ,
|
|
|
|
|
CStringGetDatum(stmt->policy_name));
|
|
|
|
|
|
|
|
|
|
sscan = systable_beginscan(pg_rowsecurity_rel,
|
|
|
|
|
RowSecurityRelidPolnameIndexId, true, NULL, 2,
|
|
|
|
|
sscan = systable_beginscan(pg_policy_rel,
|
|
|
|
|
PolicyPolrelidPolnameIndexId, true, NULL, 2,
|
|
|
|
|
skey);
|
|
|
|
|
|
|
|
|
|
rsec_tuple = systable_getnext(sscan);
|
|
|
|
|
policy_tuple = systable_getnext(sscan);
|
|
|
|
|
|
|
|
|
|
/* Check that the policy is found, raise an error if not. */
|
|
|
|
|
if (!HeapTupleIsValid(rsec_tuple))
|
|
|
|
|
if (!HeapTupleIsValid(policy_tuple))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
|
|
|
errmsg("policy \"%s\" on table \"%s\" does not exist",
|
|
|
|
@ -736,18 +735,18 @@ AlterPolicy(AlterPolicyStmt *stmt)
|
|
|
|
|
RelationGetRelationName(target_table))));
|
|
|
|
|
|
|
|
|
|
/* Get policy command */
|
|
|
|
|
cmd_datum = heap_getattr(rsec_tuple, Anum_pg_rowsecurity_rseccmd,
|
|
|
|
|
RelationGetDescr(pg_rowsecurity_rel),
|
|
|
|
|
&rseccmd_isnull);
|
|
|
|
|
if (rseccmd_isnull)
|
|
|
|
|
rseccmd = 0;
|
|
|
|
|
cmd_datum = heap_getattr(policy_tuple, Anum_pg_policy_polcmd,
|
|
|
|
|
RelationGetDescr(pg_policy_rel),
|
|
|
|
|
&polcmd_isnull);
|
|
|
|
|
if (polcmd_isnull)
|
|
|
|
|
polcmd = 0;
|
|
|
|
|
else
|
|
|
|
|
rseccmd = DatumGetChar(cmd_datum);
|
|
|
|
|
polcmd = DatumGetChar(cmd_datum);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* If the command is SELECT or DELETE then WITH CHECK should be NULL.
|
|
|
|
|
*/
|
|
|
|
|
if ((rseccmd == ACL_SELECT_CHR || rseccmd == ACL_DELETE_CHR)
|
|
|
|
|
if ((polcmd == ACL_SELECT_CHR || polcmd == ACL_DELETE_CHR)
|
|
|
|
|
&& stmt->with_check != NULL)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
@ -757,52 +756,52 @@ AlterPolicy(AlterPolicyStmt *stmt)
|
|
|
|
|
* If the command is INSERT then WITH CHECK should be the only
|
|
|
|
|
* expression provided.
|
|
|
|
|
*/
|
|
|
|
|
if ((rseccmd == ACL_INSERT_CHR)
|
|
|
|
|
if ((polcmd == ACL_INSERT_CHR)
|
|
|
|
|
&& stmt->qual != NULL)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_SYNTAX_ERROR),
|
|
|
|
|
errmsg("only WITH CHECK expression allowed for INSERT")));
|
|
|
|
|
|
|
|
|
|
rowsec_id = HeapTupleGetOid(rsec_tuple);
|
|
|
|
|
policy_id = HeapTupleGetOid(policy_tuple);
|
|
|
|
|
|
|
|
|
|
if (role_ids != NULL)
|
|
|
|
|
{
|
|
|
|
|
replaces[Anum_pg_rowsecurity_rsecroles - 1] = true;
|
|
|
|
|
values[Anum_pg_rowsecurity_rsecroles - 1] = PointerGetDatum(role_ids);
|
|
|
|
|
replaces[Anum_pg_policy_polroles - 1] = true;
|
|
|
|
|
values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (qual != NULL)
|
|
|
|
|
{
|
|
|
|
|
replaces[Anum_pg_rowsecurity_rsecqual - 1] = true;
|
|
|
|
|
values[Anum_pg_rowsecurity_rsecqual - 1]
|
|
|
|
|
replaces[Anum_pg_policy_polqual - 1] = true;
|
|
|
|
|
values[Anum_pg_policy_polqual - 1]
|
|
|
|
|
= CStringGetTextDatum(nodeToString(qual));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (with_check_qual != NULL)
|
|
|
|
|
{
|
|
|
|
|
replaces[Anum_pg_rowsecurity_rsecwithcheck - 1] = true;
|
|
|
|
|
values[Anum_pg_rowsecurity_rsecwithcheck - 1]
|
|
|
|
|
replaces[Anum_pg_policy_polwithcheck - 1] = true;
|
|
|
|
|
values[Anum_pg_policy_polwithcheck - 1]
|
|
|
|
|
= CStringGetTextDatum(nodeToString(with_check_qual));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
new_tuple = heap_modify_tuple(rsec_tuple,
|
|
|
|
|
RelationGetDescr(pg_rowsecurity_rel),
|
|
|
|
|
new_tuple = heap_modify_tuple(policy_tuple,
|
|
|
|
|
RelationGetDescr(pg_policy_rel),
|
|
|
|
|
values, isnull, replaces);
|
|
|
|
|
simple_heap_update(pg_rowsecurity_rel, &new_tuple->t_self, new_tuple);
|
|
|
|
|
simple_heap_update(pg_policy_rel, &new_tuple->t_self, new_tuple);
|
|
|
|
|
|
|
|
|
|
/* Update Catalog Indexes */
|
|
|
|
|
CatalogUpdateIndexes(pg_rowsecurity_rel, new_tuple);
|
|
|
|
|
CatalogUpdateIndexes(pg_policy_rel, new_tuple);
|
|
|
|
|
|
|
|
|
|
/* Update Dependencies. */
|
|
|
|
|
deleteDependencyRecordsFor(RowSecurityRelationId, rowsec_id, false);
|
|
|
|
|
deleteDependencyRecordsFor(PolicyRelationId, policy_id, false);
|
|
|
|
|
|
|
|
|
|
/* Record Dependencies */
|
|
|
|
|
target.classId = RelationRelationId;
|
|
|
|
|
target.objectId = table_id;
|
|
|
|
|
target.objectSubId = 0;
|
|
|
|
|
|
|
|
|
|
myself.classId = RowSecurityRelationId;
|
|
|
|
|
myself.objectId = rowsec_id;
|
|
|
|
|
myself.classId = PolicyRelationId;
|
|
|
|
|
myself.objectId = policy_id;
|
|
|
|
|
myself.objectSubId = 0;
|
|
|
|
|
|
|
|
|
|
recordDependencyOn(&myself, &target, DEPENDENCY_AUTO);
|
|
|
|
@ -820,9 +819,9 @@ AlterPolicy(AlterPolicyStmt *stmt)
|
|
|
|
|
/* Clean up. */
|
|
|
|
|
systable_endscan(sscan);
|
|
|
|
|
relation_close(target_table, NoLock);
|
|
|
|
|
heap_close(pg_rowsecurity_rel, RowExclusiveLock);
|
|
|
|
|
heap_close(pg_policy_rel, RowExclusiveLock);
|
|
|
|
|
|
|
|
|
|
return rowsec_id;
|
|
|
|
|
return policy_id;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -832,13 +831,13 @@ AlterPolicy(AlterPolicyStmt *stmt)
|
|
|
|
|
Oid
|
|
|
|
|
rename_policy(RenameStmt *stmt)
|
|
|
|
|
{
|
|
|
|
|
Relation pg_rowsecurity_rel;
|
|
|
|
|
Relation pg_policy_rel;
|
|
|
|
|
Relation target_table;
|
|
|
|
|
Oid table_id;
|
|
|
|
|
Oid opoloid;
|
|
|
|
|
ScanKeyData skey[2];
|
|
|
|
|
SysScanDesc sscan;
|
|
|
|
|
HeapTuple rsec_tuple;
|
|
|
|
|
HeapTuple policy_tuple;
|
|
|
|
|
|
|
|
|
|
/* Get id of table. Also handles permissions checks. */
|
|
|
|
|
table_id = RangeVarGetRelidExtended(stmt->relation, AccessExclusiveLock,
|
|
|
|
@ -848,74 +847,74 @@ rename_policy(RenameStmt *stmt)
|
|
|
|
|
|
|
|
|
|
target_table = relation_open(table_id, NoLock);
|
|
|
|
|
|
|
|
|
|
pg_rowsecurity_rel = heap_open(RowSecurityRelationId, RowExclusiveLock);
|
|
|
|
|
pg_policy_rel = heap_open(PolicyRelationId, RowExclusiveLock);
|
|
|
|
|
|
|
|
|
|
/* First pass -- check for conflict */
|
|
|
|
|
|
|
|
|
|
/* Add key - row security relation id. */
|
|
|
|
|
/* Add key - policy's relation id. */
|
|
|
|
|
ScanKeyInit(&skey[0],
|
|
|
|
|
Anum_pg_rowsecurity_rsecrelid,
|
|
|
|
|
Anum_pg_policy_polrelid,
|
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
|
ObjectIdGetDatum(table_id));
|
|
|
|
|
|
|
|
|
|
/* Add key - row security policy name. */
|
|
|
|
|
/* Add key - policy's name. */
|
|
|
|
|
ScanKeyInit(&skey[1],
|
|
|
|
|
Anum_pg_rowsecurity_rsecpolname,
|
|
|
|
|
Anum_pg_policy_polname,
|
|
|
|
|
BTEqualStrategyNumber, F_NAMEEQ,
|
|
|
|
|
CStringGetDatum(stmt->newname));
|
|
|
|
|
|
|
|
|
|
sscan = systable_beginscan(pg_rowsecurity_rel,
|
|
|
|
|
RowSecurityRelidPolnameIndexId, true, NULL, 2,
|
|
|
|
|
sscan = systable_beginscan(pg_policy_rel,
|
|
|
|
|
PolicyPolrelidPolnameIndexId, true, NULL, 2,
|
|
|
|
|
skey);
|
|
|
|
|
|
|
|
|
|
if (HeapTupleIsValid(systable_getnext(sscan)))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_DUPLICATE_OBJECT),
|
|
|
|
|
errmsg("row-policy \"%s\" for table \"%s\" already exists",
|
|
|
|
|
errmsg("policy \"%s\" for table \"%s\" already exists",
|
|
|
|
|
stmt->newname, RelationGetRelationName(target_table))));
|
|
|
|
|
|
|
|
|
|
systable_endscan(sscan);
|
|
|
|
|
|
|
|
|
|
/* Second pass -- find existing policy and update */
|
|
|
|
|
/* Add key - row security relation id. */
|
|
|
|
|
/* Add key - policy's relation id. */
|
|
|
|
|
ScanKeyInit(&skey[0],
|
|
|
|
|
Anum_pg_rowsecurity_rsecrelid,
|
|
|
|
|
Anum_pg_policy_polrelid,
|
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
|
ObjectIdGetDatum(table_id));
|
|
|
|
|
|
|
|
|
|
/* Add key - row security policy name. */
|
|
|
|
|
/* Add key - policy's name. */
|
|
|
|
|
ScanKeyInit(&skey[1],
|
|
|
|
|
Anum_pg_rowsecurity_rsecpolname,
|
|
|
|
|
Anum_pg_policy_polname,
|
|
|
|
|
BTEqualStrategyNumber, F_NAMEEQ,
|
|
|
|
|
CStringGetDatum(stmt->subname));
|
|
|
|
|
|
|
|
|
|
sscan = systable_beginscan(pg_rowsecurity_rel,
|
|
|
|
|
RowSecurityRelidPolnameIndexId, true, NULL, 2,
|
|
|
|
|
sscan = systable_beginscan(pg_policy_rel,
|
|
|
|
|
PolicyPolrelidPolnameIndexId, true, NULL, 2,
|
|
|
|
|
skey);
|
|
|
|
|
|
|
|
|
|
rsec_tuple = systable_getnext(sscan);
|
|
|
|
|
policy_tuple = systable_getnext(sscan);
|
|
|
|
|
|
|
|
|
|
/* Complain if we did not find the policy */
|
|
|
|
|
if (!HeapTupleIsValid(rsec_tuple))
|
|
|
|
|
if (!HeapTupleIsValid(policy_tuple))
|
|
|
|
|
ereport(ERROR,
|
|
|
|
|
(errcode(ERRCODE_UNDEFINED_OBJECT),
|
|
|
|
|
errmsg("row-policy \"%s\" for table \"%s\" does not exist",
|
|
|
|
|
errmsg("policy \"%s\" for table \"%s\" does not exist",
|
|
|
|
|
stmt->subname, RelationGetRelationName(target_table))));
|
|
|
|
|
|
|
|
|
|
opoloid = HeapTupleGetOid(rsec_tuple);
|
|
|
|
|
opoloid = HeapTupleGetOid(policy_tuple);
|
|
|
|
|
|
|
|
|
|
rsec_tuple = heap_copytuple(rsec_tuple);
|
|
|
|
|
policy_tuple = heap_copytuple(policy_tuple);
|
|
|
|
|
|
|
|
|
|
namestrcpy(&((Form_pg_rowsecurity) GETSTRUCT(rsec_tuple))->rsecpolname,
|
|
|
|
|
namestrcpy(&((Form_pg_policy) GETSTRUCT(policy_tuple))->polname,
|
|
|
|
|
stmt->newname);
|
|
|
|
|
|
|
|
|
|
simple_heap_update(pg_rowsecurity_rel, &rsec_tuple->t_self, rsec_tuple);
|
|
|
|
|
simple_heap_update(pg_policy_rel, &policy_tuple->t_self, policy_tuple);
|
|
|
|
|
|
|
|
|
|
/* keep system catalog indexes current */
|
|
|
|
|
CatalogUpdateIndexes(pg_rowsecurity_rel, rsec_tuple);
|
|
|
|
|
CatalogUpdateIndexes(pg_policy_rel, policy_tuple);
|
|
|
|
|
|
|
|
|
|
InvokeObjectPostAlterHook(RowSecurityRelationId,
|
|
|
|
|
HeapTupleGetOid(rsec_tuple), 0);
|
|
|
|
|
InvokeObjectPostAlterHook(PolicyRelationId,
|
|
|
|
|
HeapTupleGetOid(policy_tuple), 0);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Invalidate relation's relcache entry so that other backends (and
|
|
|
|
@ -926,7 +925,7 @@ rename_policy(RenameStmt *stmt)
|
|
|
|
|
|
|
|
|
|
/* Clean up. */
|
|
|
|
|
systable_endscan(sscan);
|
|
|
|
|
heap_close(pg_rowsecurity_rel, RowExclusiveLock);
|
|
|
|
|
heap_close(pg_policy_rel, RowExclusiveLock);
|
|
|
|
|
relation_close(target_table, NoLock);
|
|
|
|
|
|
|
|
|
|
return opoloid;
|
|
|
|
@ -941,33 +940,33 @@ rename_policy(RenameStmt *stmt)
|
|
|
|
|
Oid
|
|
|
|
|
get_relation_policy_oid(Oid relid, const char *policy_name, bool missing_ok)
|
|
|
|
|
{
|
|
|
|
|
Relation pg_rowsecurity_rel;
|
|
|
|
|
Relation pg_policy_rel;
|
|
|
|
|
ScanKeyData skey[2];
|
|
|
|
|
SysScanDesc sscan;
|
|
|
|
|
HeapTuple rsec_tuple;
|
|
|
|
|
HeapTuple policy_tuple;
|
|
|
|
|
Oid policy_oid;
|
|
|
|
|
|
|
|
|
|
pg_rowsecurity_rel = heap_open(RowSecurityRelationId, AccessShareLock);
|
|
|
|
|
pg_policy_rel = heap_open(PolicyRelationId, AccessShareLock);
|
|
|
|
|
|
|
|
|
|
/* Add key - row security relation id. */
|
|
|
|
|
/* Add key - policy's relation id. */
|
|
|
|
|
ScanKeyInit(&skey[0],
|
|
|
|
|
Anum_pg_rowsecurity_rsecrelid,
|
|
|
|
|
Anum_pg_policy_polrelid,
|
|
|
|
|
BTEqualStrategyNumber, F_OIDEQ,
|
|
|
|
|
ObjectIdGetDatum(relid));
|
|
|
|
|
|
|
|
|
|
/* Add key - row security policy name. */
|
|
|
|
|
/* Add key - policy's name. */
|
|
|
|
|
ScanKeyInit(&skey[1],
|
|
|
|
|
Anum_pg_rowsecurity_rsecpolname,
|
|
|
|
|
Anum_pg_policy_polname,
|
|
|
|
|
BTEqualStrategyNumber, F_NAMEEQ,
|
|
|
|
|
CStringGetDatum(policy_name));
|
|
|
|
|
|
|
|
|
|
sscan = systable_beginscan(pg_rowsecurity_rel,
|
|
|
|
|
RowSecurityRelidPolnameIndexId, true, NULL, 2,
|
|
|
|
|
sscan = systable_beginscan(pg_policy_rel,
|
|
|
|
|
PolicyPolrelidPolnameIndexId, true, NULL, 2,
|
|
|
|
|
skey);
|
|
|
|
|
|
|
|
|
|
rsec_tuple = systable_getnext(sscan);
|
|
|
|
|
policy_tuple = systable_getnext(sscan);
|
|
|
|
|
|
|
|
|
|
if (!HeapTupleIsValid(rsec_tuple))
|
|
|
|
|
if (!HeapTupleIsValid(policy_tuple))
|
|
|
|
|
{
|
|
|
|
|
if (!missing_ok)
|
|
|
|
|
ereport(ERROR,
|
|
|
|
@ -978,11 +977,11 @@ get_relation_policy_oid(Oid relid, const char *policy_name, bool missing_ok)
|
|
|
|
|
policy_oid = InvalidOid;
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
policy_oid = HeapTupleGetOid(rsec_tuple);
|
|
|
|
|
policy_oid = HeapTupleGetOid(policy_tuple);
|
|
|
|
|
|
|
|
|
|
/* Clean up. */
|
|
|
|
|
systable_endscan(sscan);
|
|
|
|
|
heap_close(pg_rowsecurity_rel, AccessShareLock);
|
|
|
|
|
heap_close(pg_policy_rel, AccessShareLock);
|
|
|
|
|
|
|
|
|
|
return policy_oid;
|
|
|
|
|
}
|
|
|
|
|