diff options
Diffstat (limited to 'src/backend')
| -rw-r--r-- | src/backend/catalog/Makefile | 2 | ||||
| -rw-r--r-- | src/backend/catalog/dependency.c | 11 | ||||
| -rw-r--r-- | src/backend/catalog/objectaddress.c | 58 | ||||
| -rw-r--r-- | src/backend/catalog/system_views.sql | 18 | ||||
| -rw-r--r-- | src/backend/commands/copy.c | 48 | ||||
| -rw-r--r-- | src/backend/commands/event_trigger.c | 2 | ||||
| -rw-r--r-- | src/backend/commands/functioncmds.c | 6 | ||||
| -rw-r--r-- | src/backend/commands/policy.c | 317 | ||||
| -rw-r--r-- | src/backend/commands/tablecmds.c | 19 | ||||
| -rw-r--r-- | src/backend/executor/execMain.c | 2 | ||||
| -rw-r--r-- | src/backend/optimizer/path/allpaths.c | 2 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/planner.c | 6 | ||||
| -rw-r--r-- | src/backend/optimizer/plan/setrefs.c | 8 | ||||
| -rw-r--r-- | src/backend/parser/gram.y | 11 | ||||
| -rw-r--r-- | src/backend/rewrite/rewriteHandler.c | 4 | ||||
| -rw-r--r-- | src/backend/rewrite/rowsecurity.c | 14 | ||||
| -rw-r--r-- | src/backend/utils/cache/plancache.c | 8 | ||||
| -rw-r--r-- | src/backend/utils/cache/relcache.c | 4 |
18 files changed, 310 insertions, 230 deletions
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index b257b02ff5c..a403c643600 100644 --- a/src/backend/catalog/Makefile +++ b/src/backend/catalog/Makefile @@ -39,7 +39,7 @@ POSTGRES_BKI_SRCS = $(addprefix $(top_srcdir)/src/include/catalog/,\ pg_ts_config.h pg_ts_config_map.h pg_ts_dict.h \ pg_ts_parser.h pg_ts_template.h pg_extension.h \ pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \ - pg_foreign_table.h pg_rowsecurity.h \ + pg_foreign_table.h pg_policy.h \ pg_default_acl.h pg_seclabel.h pg_shseclabel.h pg_collation.h pg_range.h \ toasting.h indexing.h \ ) diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c index f338acf827d..8ba5123c101 100644 --- a/src/backend/catalog/dependency.c +++ b/src/backend/catalog/dependency.c @@ -43,9 +43,9 @@ #include "catalog/pg_opclass.h" #include "catalog/pg_operator.h" #include "catalog/pg_opfamily.h" +#include "catalog/pg_policy.h" #include "catalog/pg_proc.h" #include "catalog/pg_rewrite.h" -#include "catalog/pg_rowsecurity.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_trigger.h" #include "catalog/pg_ts_config.h" @@ -156,7 +156,8 @@ static const Oid object_classes[MAX_OCLASS] = { UserMappingRelationId, /* OCLASS_USER_MAPPING */ DefaultAclRelationId, /* OCLASS_DEFACL */ ExtensionRelationId, /* OCLASS_EXTENSION */ - EventTriggerRelationId /* OCLASS_EVENT_TRIGGER */ + EventTriggerRelationId, /* OCLASS_EVENT_TRIGGER */ + PolicyRelationId /* OCLASS_POLICY */ }; @@ -1251,7 +1252,7 @@ doDeletion(const ObjectAddress *object, int flags) RemoveEventTriggerById(object->objectId); break; - case OCLASS_ROWSECURITY: + case OCLASS_POLICY: RemovePolicyById(object->objectId); break; @@ -2361,8 +2362,8 @@ getObjectClass(const ObjectAddress *object) case EventTriggerRelationId: return OCLASS_EVENT_TRIGGER; - case RowSecurityRelationId: - return OCLASS_ROWSECURITY; + case PolicyRelationId: + return OCLASS_POLICY; } /* shouldn't get here */ diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c index b69b75bcc2e..e261307e9d5 100644 --- a/src/backend/catalog/objectaddress.c +++ b/src/backend/catalog/objectaddress.c @@ -42,7 +42,7 @@ #include "catalog/pg_opfamily.h" #include "catalog/pg_operator.h" #include "catalog/pg_proc.h" -#include "catalog/pg_rowsecurity.h" +#include "catalog/pg_policy.h" #include "catalog/pg_rewrite.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_trigger.h" @@ -346,11 +346,11 @@ static const ObjectPropertyType ObjectProperty[] = false }, { - RowSecurityRelationId, - RowSecurityOidIndexId, + PolicyRelationId, + PolicyOidIndexId, -1, -1, - Anum_pg_rowsecurity_rsecpolname, + Anum_pg_policy_polname, InvalidAttrNumber, InvalidAttrNumber, InvalidAttrNumber, @@ -998,7 +998,7 @@ get_object_address_relobject(ObjectType objtype, List *objname, address.objectSubId = 0; break; case OBJECT_POLICY: - address.classId = RowSecurityRelationId; + address.classId = PolicyRelationId; address.objectId = relation ? get_relation_policy_oid(reloid, depname, missing_ok) : InvalidOid; @@ -2189,38 +2189,38 @@ getObjectDescription(const ObjectAddress *object) break; } - case OCLASS_ROWSECURITY: + case OCLASS_POLICY: { - Relation rsec_rel; + Relation policy_rel; ScanKeyData skey[1]; SysScanDesc sscan; HeapTuple tuple; - Form_pg_rowsecurity form_rsec; + Form_pg_policy form_policy; - rsec_rel = heap_open(RowSecurityRelationId, AccessShareLock); + policy_rel = heap_open(PolicyRelationId, AccessShareLock); ScanKeyInit(&skey[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(object->objectId)); - sscan = systable_beginscan(rsec_rel, RowSecurityOidIndexId, + sscan = systable_beginscan(policy_rel, PolicyOidIndexId, true, NULL, 1, skey); tuple = systable_getnext(sscan); if (!HeapTupleIsValid(tuple)) - elog(ERROR, "cache lookup failed for row-security relation %u", + elog(ERROR, "cache lookup failed for policy %u", object->objectId); - form_rsec = (Form_pg_rowsecurity) GETSTRUCT(tuple); + form_policy = (Form_pg_policy) GETSTRUCT(tuple); appendStringInfo(&buffer, _("policy %s on "), - NameStr(form_rsec->rsecpolname)); - getRelationDescription(&buffer, form_rsec->rsecrelid); + NameStr(form_policy->polname)); + getRelationDescription(&buffer, form_policy->polrelid); systable_endscan(sscan); - heap_close(rsec_rel, AccessShareLock); + heap_close(policy_rel, AccessShareLock); break; } @@ -2635,6 +2635,10 @@ getObjectTypeDescription(const ObjectAddress *object) appendStringInfoString(&buffer, "event trigger"); break; + case OCLASS_POLICY: + appendStringInfoString(&buffer, "policy"); + break; + default: appendStringInfo(&buffer, "unrecognized %u", object->classId); break; @@ -3119,6 +3123,30 @@ getObjectIdentity(const ObjectAddress *object) break; } + case OCLASS_POLICY: + { + Relation polDesc; + HeapTuple tup; + Form_pg_policy policy; + + polDesc = heap_open(PolicyRelationId, AccessShareLock); + + tup = get_catalog_object_by_oid(polDesc, object->objectId); + + if (!HeapTupleIsValid(tup)) + elog(ERROR, "could not find tuple for policy %u", + object->objectId); + + policy = (Form_pg_policy) GETSTRUCT(tup); + + appendStringInfo(&buffer, "%s on ", + quote_identifier(NameStr(policy->polname))); + getRelationIdentity(&buffer, policy->polrelid); + + heap_close(polDesc, AccessShareLock); + break; + } + case OCLASS_SCHEMA: { char *nspname; diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql index a819952c75d..22b8ceef622 100644 --- a/src/backend/catalog/system_views.sql +++ b/src/backend/catalog/system_views.sql @@ -67,30 +67,30 @@ CREATE VIEW pg_policies AS SELECT N.nspname AS schemaname, C.relname AS tablename, - rs.rsecpolname AS policyname, + pol.polname AS policyname, CASE - WHEN rs.rsecroles = '{0}' THEN + WHEN pol.polroles = '{0}' THEN string_to_array('public', '') ELSE ARRAY ( SELECT rolname FROM pg_catalog.pg_authid - WHERE oid = ANY (rs.rsecroles) ORDER BY 1 + WHERE oid = ANY (pol.polroles) ORDER BY 1 ) END AS roles, - CASE WHEN rs.rseccmd IS NULL THEN 'ALL' ELSE - CASE rs.rseccmd + CASE WHEN pol.polcmd IS NULL THEN 'ALL' ELSE + CASE pol.polcmd WHEN 'r' THEN 'SELECT' WHEN 'a' THEN 'INSERT' WHEN 'u' THEN 'UPDATE' WHEN 'd' THEN 'DELETE' END END AS cmd, - pg_catalog.pg_get_expr(rs.rsecqual, rs.rsecrelid) AS qual, - pg_catalog.pg_get_expr(rs.rsecwithcheck, rs.rsecrelid) AS with_check - FROM pg_catalog.pg_rowsecurity rs - JOIN pg_catalog.pg_class C ON (C.oid = rs.rsecrelid) + pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS qual, + pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS with_check + FROM pg_catalog.pg_policy pol + JOIN pg_catalog.pg_class C ON (C.oid = pol.polrelid) LEFT JOIN pg_catalog.pg_namespace N ON (N.oid = C.relnamespace); CREATE VIEW pg_rules AS diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c index 83e8f891222..08abe141f41 100644 --- a/src/backend/commands/copy.c +++ b/src/backend/commands/copy.c @@ -282,12 +282,13 @@ static const char BinarySignature[11] = "PGCOPY\n\377\r\n\0"; /* non-export function prototypes */ static CopyState BeginCopy(bool is_from, Relation rel, Node *raw_query, - const char *queryString, List *attnamelist, List *options); + const char *queryString, const Oid queryRelId, List *attnamelist, + List *options); static void EndCopy(CopyState cstate); static void ClosePipeToProgram(CopyState cstate); static CopyState BeginCopyTo(Relation rel, Node *query, const char *queryString, - const char *filename, bool is_program, List *attnamelist, - List *options); + const Oid queryRelId, const char *filename, bool is_program, + List *attnamelist, List *options); static void EndCopyTo(CopyState cstate); static uint64 DoCopyTo(CopyState cstate); static uint64 CopyTo(CopyState cstate); @@ -843,7 +844,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) ExecCheckRTPerms(list_make1(rte), true); /* - * Permission check for row security. + * Permission check for row security policies. * * check_enable_rls will ereport(ERROR) if the user has requested * something invalid and will otherwise indicate if we should enable @@ -866,7 +867,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) if (is_from) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("COPY FROM not supported with row security."), + errmsg("COPY FROM not supported with row level security."), errhint("Use direct INSERT statements instead."))); /* Build target list */ @@ -886,7 +887,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) target->location = 1; /* Build FROM clause */ - from = makeRangeVar(NULL, RelationGetRelationName(rel), 1); + from = stmt->relation; /* Build query */ select = makeNode(SelectStmt); @@ -895,8 +896,6 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) query = (Node*) select; - relid = InvalidOid; - /* Close the handle to the relation as it is no longer needed. */ heap_close(rel, (is_from ? RowExclusiveLock : AccessShareLock)); rel = NULL; @@ -926,7 +925,7 @@ DoCopy(const CopyStmt *stmt, const char *queryString, uint64 *processed) } else { - cstate = BeginCopyTo(rel, query, queryString, + cstate = BeginCopyTo(rel, query, queryString, relid, stmt->filename, stmt->is_program, stmt->attlist, stmt->options); *processed = DoCopyTo(cstate); /* copy from database to file */ @@ -1304,6 +1303,7 @@ BeginCopy(bool is_from, Relation rel, Node *raw_query, const char *queryString, + const Oid queryRelId, List *attnamelist, List *options) { @@ -1395,6 +1395,30 @@ BeginCopy(bool is_from, plan = planner(query, 0, NULL); /* + * If we were passed in a relid, make sure we got the same one back + * after planning out the query. It's possible that it changed between + * when we checked the policies on the table and decided to use a query + * and now. + */ + if (queryRelId != InvalidOid) + { + Oid relid = linitial_oid(plan->relationOids); + + /* + * There should only be one relationOid in this case, since we will + * only get here when we have changed the command for the user from + * a "COPY relation TO" to "COPY (SELECT * FROM relation) TO", to + * allow row level security policies to be applied. + */ + Assert(list_length(plan->relationOids) == 1); + + if (relid != queryRelId) + ereport(ERROR, + (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), + errmsg("relation referenced by COPY statement has changed"))); + } + + /* * Use a snapshot with an updated command ID to ensure this query sees * results of any previously executed queries. */ @@ -1595,6 +1619,7 @@ static CopyState BeginCopyTo(Relation rel, Node *query, const char *queryString, + const Oid queryRelId, const char *filename, bool is_program, List *attnamelist, @@ -1636,7 +1661,8 @@ BeginCopyTo(Relation rel, RelationGetRelationName(rel)))); } - cstate = BeginCopy(false, rel, query, queryString, attnamelist, options); + cstate = BeginCopy(false, rel, query, queryString, queryRelId, attnamelist, + options); oldcontext = MemoryContextSwitchTo(cstate->copycontext); if (pipe) @@ -2565,7 +2591,7 @@ BeginCopyFrom(Relation rel, MemoryContext oldcontext; bool volatile_defexprs; - cstate = BeginCopy(true, rel, NULL, NULL, attnamelist, options); + cstate = BeginCopy(true, rel, NULL, NULL, InvalidOid, attnamelist, options); oldcontext = MemoryContextSwitchTo(cstate->copycontext); /* Initialize state variables */ diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c index 1b8c94bcfdf..6a3002f5268 100644 --- a/src/backend/commands/event_trigger.c +++ b/src/backend/commands/event_trigger.c @@ -997,7 +997,7 @@ EventTriggerSupportsObjectClass(ObjectClass objclass) case OCLASS_USER_MAPPING: case OCLASS_DEFACL: case OCLASS_EXTENSION: - case OCLASS_ROWSECURITY: + case OCLASS_POLICY: return true; case MAX_OCLASS: diff --git a/src/backend/commands/functioncmds.c b/src/backend/commands/functioncmds.c index 470db5705cc..d3a59aa3567 100644 --- a/src/backend/commands/functioncmds.c +++ b/src/backend/commands/functioncmds.c @@ -904,9 +904,9 @@ CreateFunction(CreateFunctionStmt *stmt, const char *queryString) ReleaseSysCache(languageTuple); /* - * Only superuser is allowed to create leakproof functions because it - * possibly allows unprivileged users to reference invisible tuples to be - * filtered out using views for row-level security. + * Only superuser is allowed to create leakproof functions because leakproof + * functions can see tuples which have not yet been filtered out by security + * barrier views or row level security policies. */ if (isLeakProof && !superuser()) ereport(ERROR, diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c index 10d230ef431..290c826a680 100644 --- a/src/backend/commands/policy.c +++ b/src/backend/commands/policy.c @@ -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; } diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 56294552e71..2333e1bed92 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -37,7 +37,6 @@ #include "catalog/pg_inherits_fn.h" #include "catalog/pg_namespace.h" #include "catalog/pg_opclass.h" -#include "catalog/pg_rowsecurity.h" #include "catalog/pg_tablespace.h" #include "catalog/pg_trigger.h" #include "catalog/pg_type.h" @@ -7986,6 +7985,24 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel, colName))); break; + case OCLASS_POLICY: + + /* + * A policy can depend on a column because the column is + * specified in the policy's USING or WITH CHECK qual + * expressions. It might be possible to rewrite and recheck + * the policy expression, but punt for now. It's certainly + * easy enough to remove and recreate the policy; still, + * FIXME someday. + */ + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("cannot alter type of a column used in a policy definition"), + errdetail("%s depends on column \"%s\"", + getObjectDescription(&foundObject), + colName))); + break; + case OCLASS_DEFAULT: /* diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index a753b207008..c499486f016 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -502,7 +502,7 @@ ExecutorRewind(QueryDesc *queryDesc) * Returns true if permissions are adequate. Otherwise, throws an appropriate * error if ereport_on_violation is true, or simply returns false otherwise. * - * Note that this does NOT address row-level security policies (aka: RLS). If + * Note that this does NOT address row level security policies (aka: RLS). If * rows will be returned to the user as a result of this permission check * passing, then RLS also needs to be consulted (and check_enable_rls()). * diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c index c97355e8fda..25f30676f02 100644 --- a/src/backend/optimizer/path/allpaths.c +++ b/src/backend/optimizer/path/allpaths.c @@ -1171,7 +1171,7 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel, /* * If the subquery has the "security_barrier" flag, it means the subquery - * originated from a view that must enforce row-level security. Then we + * originated from a view that must enforce row level security. Then we * must not push down quals that contain leaky functions. (Ideally this * would be checked inside subquery_is_pushdown_safe, but since we don't * currently pass the RTE to that function, we must do it here.) diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index fb74d6bf1f4..f752ecc16a5 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -177,7 +177,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) glob->lastPHId = 0; glob->lastRowMarkId = 0; glob->transientPlan = false; - glob->has_rls = false; + glob->hasRowSecurity = false; /* Determine what fraction of the plan is likely to be scanned */ if (cursorOptions & CURSOR_OPT_FAST_PLAN) @@ -255,7 +255,7 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams) result->relationOids = glob->relationOids; result->invalItems = glob->invalItems; result->nParamExec = glob->nParamExec; - result->has_rls = glob->has_rls; + result->hasRowSecurity = glob->hasRowSecurity; return result; } @@ -1208,7 +1208,7 @@ grouping_planner(PlannerInfo *root, double tuple_fraction) * This may add new security barrier subquery RTEs to the rangetable. */ expand_security_quals(root, tlist); - root->glob->has_rls = parse->hasRowSecurity; + root->glob->hasRowSecurity = parse->hasRowSecurity; /* * Locate any window functions in the tlist. (We don't need to look diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index e630d0b6d81..4d3fbca5969 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -2109,7 +2109,7 @@ extract_query_dependencies(Node *query, glob.type = T_PlannerGlobal; glob.relationOids = NIL; glob.invalItems = NIL; - glob.has_rls = false; + glob.hasRowSecurity = false; MemSet(&root, 0, sizeof(root)); root.type = T_PlannerInfo; @@ -2119,7 +2119,7 @@ extract_query_dependencies(Node *query, *relationOids = glob.relationOids; *invalItems = glob.invalItems; - *hasRowSecurity = glob.has_rls; + *hasRowSecurity = glob.hasRowSecurity; } static bool @@ -2135,8 +2135,8 @@ extract_query_dependencies_walker(Node *node, PlannerInfo *context) Query *query = (Query *) node; ListCell *lc; - /* Collect row-security information */ - context->glob->has_rls = query->hasRowSecurity; + /* Collect row security information */ + context->glob->hasRowSecurity = query->hasRowSecurity; if (query->commandType == CMD_UTILITY) { diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index bd180e7e87b..7e48958ae85 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -5535,7 +5535,7 @@ opt_restart_seqs: * COMMENT ON [ [ CONVERSION | COLLATION | DATABASE | DOMAIN | * EXTENSION | EVENT TRIGGER | FOREIGN DATA WRAPPER | * FOREIGN TABLE | INDEX | [PROCEDURAL] LANGUAGE | - * MATERIALIZED VIEW | ROLE | SCHEMA | SEQUENCE | + * MATERIALIZED VIEW | POLICY | ROLE | SCHEMA | SEQUENCE | * SERVER | TABLE | TABLESPACE | * TEXT SEARCH CONFIGURATION | TEXT SEARCH DICTIONARY | * TEXT SEARCH PARSER | TEXT SEARCH TEMPLATE | TYPE | @@ -5601,6 +5601,15 @@ CommentStmt: n->comment = $8; $$ = (Node *) n; } + | COMMENT ON POLICY name ON any_name IS comment_text + { + CommentStmt *n = makeNode(CommentStmt); + n->objtype = OBJECT_POLICY; + n->objname = lappend($6, makeString($4)); + n->objargs = NIL; + n->comment = $8; + $$ = (Node *) n; + } | COMMENT ON RULE name ON any_name IS comment_text { CommentStmt *n = makeNode(CommentStmt); diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index e7021509017..ad983c7158b 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -1715,7 +1715,7 @@ fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown) } } /* - * If the RTE has row-security quals, apply them and recurse into the + * If the RTE has row security quals, apply them and recurse into the * securityQuals. */ if (prepend_row_security_policies(parsetree, rte, rt_index)) @@ -1727,7 +1727,7 @@ fireRIRrules(Query *parsetree, List *activeRIRs, bool forUpdatePushedDown) if (list_member_oid(activeRIRs, RelationGetRelid(rel))) ereport(ERROR, (errcode(ERRCODE_INVALID_OBJECT_DEFINITION), - errmsg("infinite recursion detected in row-security policy for relation \"%s\"", + errmsg("infinite recursion detected in policy for relation \"%s\"", RelationGetRelationName(rel)))); /* diff --git a/src/backend/rewrite/rowsecurity.c b/src/backend/rewrite/rowsecurity.c index 66c358cdec9..6c232dcf9ae 100644 --- a/src/backend/rewrite/rowsecurity.c +++ b/src/backend/rewrite/rowsecurity.c @@ -1,6 +1,6 @@ /* * rewrite/rowsecurity.c - * Routines to support policies for row-level security. + * Routines to support policies for row level security (aka RLS). * * Policies in PostgreSQL provide a mechanism to limit what records are * returned to a user and what records a user is permitted to add to a table. @@ -38,7 +38,7 @@ #include "access/sysattr.h" #include "catalog/pg_class.h" #include "catalog/pg_inherits_fn.h" -#include "catalog/pg_rowsecurity.h" +#include "catalog/pg_policy.h" #include "catalog/pg_type.h" #include "miscadmin.h" #include "nodes/makefuncs.h" @@ -72,8 +72,8 @@ static bool check_role_for_policy(ArrayType *policy_roles, Oid user_id); row_security_policy_hook_type row_security_policy_hook = NULL; /* - * Check the given RTE to see whether it's already had row-security quals - * expanded and, if not, prepend any row-security rules from built-in or + * Check the given RTE to see whether it's already had row security quals + * expanded and, if not, prepend any row security rules from built-in or * plug-in sources to the securityQuals. The security quals are rewritten (for * view expansion, etc) before being added to the RTE. * @@ -154,14 +154,14 @@ prepend_row_security_policies(Query* root, RangeTblEntry* rte, int rt_index) /* * Check if this is only the default-deny policy. * - * Normally, if the table has row-security enabled but there are + * Normally, if the table has row security enabled but there are * no policies, we use a default-deny policy and not allow anything. * However, when an extension uses the hook to add their own * policies, we don't want to include the default deny policy or * there won't be any way for a user to use an extension exclusively * for the policies to be used. */ - if (((RowSecurityPolicy *) linitial(rowsec_policies))->rsecid + if (((RowSecurityPolicy *) linitial(rowsec_policies))->policy_id == InvalidOid) defaultDeny = true; @@ -353,7 +353,7 @@ pull_row_security_policies(CmdType cmd, Relation relation, Oid user_id) 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'); diff --git a/src/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c index d85ea1bbd3a..c537fe3236c 100644 --- a/src/backend/utils/cache/plancache.c +++ b/src/backend/utils/cache/plancache.c @@ -207,7 +207,7 @@ CreateCachedPlan(Node *raw_parse_tree, plansource->generic_cost = -1; plansource->total_custom_cost = 0; plansource->num_custom_plans = 0; - plansource->has_rls = false; + plansource->hasRowSecurity = false; plansource->rowSecurityDisabled = (security_context & SECURITY_ROW_LEVEL_DISABLED) != 0; plansource->row_security_env = row_security; @@ -383,7 +383,7 @@ CompleteCachedPlan(CachedPlanSource *plansource, extract_query_dependencies((Node *) querytree_list, &plansource->relationOids, &plansource->invalItems, - &plansource->has_rls); + &plansource->hasRowSecurity); /* * Also save the current search_path in the query_context. (This @@ -617,7 +617,7 @@ RevalidateCachedQuery(CachedPlanSource *plansource) */ if (plansource->is_valid && !plansource->rowSecurityDisabled - && plansource->has_rls + && plansource->hasRowSecurity && (plansource->planUserId != GetUserId() || plansource->row_security_env != row_security)) plansource->is_valid = false; @@ -766,7 +766,7 @@ RevalidateCachedQuery(CachedPlanSource *plansource) extract_query_dependencies((Node *) qlist, &plansource->relationOids, &plansource->invalItems, - &plansource->has_rls); + &plansource->hasRowSecurity); /* * Also save the current search_path in the query_context. (This should diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c index c80ef3c6f89..79244e56865 100644 --- a/src/backend/utils/cache/relcache.c +++ b/src/backend/utils/cache/relcache.c @@ -866,7 +866,7 @@ equalPolicy(RowSecurityPolicy *policy1, RowSecurityPolicy *policy2) if (policy2 == NULL) return false; - if (policy1->rsecid != policy2->rsecid) + if (policy1->policy_id != policy2->policy_id) return false; if (policy1->cmd != policy2->cmd) return false; @@ -3439,7 +3439,7 @@ RelationCacheInitializePhase3(void) * they are not preserved in the cache. Note that we can never NOT * have a policy while relrowsecurity is true, * RelationBuildRowSecurity will create a single default-deny policy - * if there is no policy defined in pg_rowsecurity. + * if there is no policy defined in pg_policy. */ if (relation->rd_rel->relrowsecurity && relation->rd_rsdesc == NULL) { |
