diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml index f98e282741f71ce2968c537dccc773970695cfd4..9ceb96b54c74bc090373050e069a25897432e458 100644 --- a/doc/src/sgml/catalogs.sgml +++ b/doc/src/sgml/catalogs.sgml @@ -239,8 +239,8 @@ </row> <row> - <entry><link linkend="catalog-pg-rowsecurity"><structname>pg_rowsecurity</structname></link></entry> - <entry>table row-level security policies</entry> + <entry><link linkend="catalog-pg-policy"><structname>pg_policy</structname></link></entry> + <entry>table policies</entry> </row> <row> @@ -1944,8 +1944,8 @@ <entry><type>bool</type></entry> <entry></entry> <entry> - True if table has row-security enabled; see - <link linkend="catalog-pg-rowsecurity"><structname>pg_rowsecurity</structname></link> catalog + True if table has row level security enabled; see + <link linkend="catalog-pg-policy"><structname>pg_policy</structname></link> catalog </entry> </row> @@ -5342,15 +5342,15 @@ </table> </sect1> - <sect1 id="catalog-pg-rowsecurity"> - <title><structname>pg_rowsecurity</structname></title> + <sect1 id="catalog-pg-policy"> + <title><structname>pg_policy</structname></title> - <indexterm zone="catalog-pg-rowsecurity"> - <primary>pg_rowsecurity</primary> + <indexterm zone="catalog-pg-policy"> + <primary>pg_policy</primary> </indexterm> <para> - The catalog <structname>pg_rowsecurity</structname> stores row-level + The catalog <structname>pg_policy</structname> stores row-level security policies for each table. A policy includes the kind of command which it applies to (or all commands), the roles which it applies to, the expression to be added as a security-barrier @@ -5361,7 +5361,7 @@ <table> - <title><structname>pg_rowsecurity</structname> Columns</title> + <title><structname>pg_policy</structname> Columns</title> <tgroup cols="4"> <thead> @@ -5375,42 +5375,42 @@ <tbody> <row> - <entry><structfield>rsecpolname</structfield></entry> + <entry><structfield>polname</structfield></entry> <entry><type>name</type></entry> <entry></entry> - <entry>The name of the row-security policy</entry> + <entry>The name of the policy</entry> </row> <row> - <entry><structfield>rsecrelid</structfield></entry> + <entry><structfield>polrelid</structfield></entry> <entry><type>oid</type></entry> <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.oid</literal></entry> - <entry>The table to which the row-security policy belongs</entry> + <entry>The table to which the policy belongs</entry> </row> <row> - <entry><structfield>rseccmd</structfield></entry> + <entry><structfield>polcmd</structfield></entry> <entry><type>char</type></entry> <entry></entry> - <entry>The command type to which the row-security policy is applied.</entry> + <entry>The command type to which the policy is applied.</entry> </row> <row> - <entry><structfield>rsecroles</structfield></entry> + <entry><structfield>polroles</structfield></entry> <entry><type>char</type></entry> <entry></entry> - <entry>The roles to which the row-security policy is applied.</entry> + <entry>The roles to which the policy is applied.</entry> </row> <row> - <entry><structfield>rsecqual</structfield></entry> + <entry><structfield>polqual</structfield></entry> <entry><type>pg_node_tree</type></entry> <entry></entry> <entry>The expression tree to be added to the security barrier qualifications for queries which use the table.</entry> </row> <row> - <entry><structfield>rsecwithcheck</structfield></entry> + <entry><structfield>polwithcheck</structfield></entry> <entry><type>pg_node_tree</type></entry> <entry></entry> <entry>The expression tree to be added to the with check qualifications for queries which attempt to add rows to the table.</entry> @@ -5423,8 +5423,8 @@ <note> <para> <literal>pg_class.relrowsecurity</literal> - True if the table has row-security enabled. Policies will not be applied - unless row-security is enabled on the table. + True if the table has row security enabled. Policies will not be applied + unless row security is enabled on the table. </para> </note> diff --git a/doc/src/sgml/ddl.sgml b/doc/src/sgml/ddl.sgml index f9dc151a0cc711df40a2cae5dedfc7e7ead2614c..570a003e4a9d37daa470dbe007342f8a824bad6c 100644 --- a/doc/src/sgml/ddl.sgml +++ b/doc/src/sgml/ddl.sgml @@ -1558,8 +1558,8 @@ REVOKE ALL ON accounts FROM PUBLIC; <para> To specify which rows are visible and what rows can be added to the - table with row security, an expression is required which returns a - boolean result. This expression will be evaluated for each row prior + table with row level security, an expression is required which returns + a boolean result. This expression will be evaluated for each row prior to other conditionals or functions which are part of the query. The one exception to this rule are <literal>leakproof</literal> functions, which are guaranteed to not leak information. Two expressions may be diff --git a/doc/src/sgml/ref/alter_policy.sgml b/doc/src/sgml/ref/alter_policy.sgml index ab717f31c51b92b82f2b59078df3ad01ff39c3d2..796035e9da92cf4bbbf1dfe07b3e5ffba7f81d35 100644 --- a/doc/src/sgml/ref/alter_policy.sgml +++ b/doc/src/sgml/ref/alter_policy.sgml @@ -16,7 +16,7 @@ PostgreSQL documentation <refnamediv> <refname>ALTER POLICY</refname> - <refpurpose>change the definition of a row-security policy</refpurpose> + <refpurpose>change the definition of a policy</refpurpose> </refnamediv> <refsynopsisdiv> @@ -34,7 +34,7 @@ ALTER POLICY <replaceable class="parameter">name</replaceable> ON <replaceable c <para> <command>ALTER POLICY</command> changes the <replaceable class="parameter"> - definition</replaceable> of an existing row-security policy. + definition</replaceable> of an existing policy. </para> <para> diff --git a/doc/src/sgml/ref/create_policy.sgml b/doc/src/sgml/ref/create_policy.sgml index eff062c114f0c59d8b78587cae3915f92a3919ce..4c8c00193139600a8741b3e9a45cbebbe9873766 100644 --- a/doc/src/sgml/ref/create_policy.sgml +++ b/doc/src/sgml/ref/create_policy.sgml @@ -16,7 +16,7 @@ PostgreSQL documentation <refnamediv> <refname>CREATE POLICY</refname> - <refpurpose>define a new row-security policy for a table</refpurpose> + <refpurpose>define a new policy for a table</refpurpose> </refnamediv> <refsynopsisdiv> @@ -33,14 +33,13 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable <title>Description</title> <para> - The <command>CREATE POLICY</command> command defines a new row-security - policy for a table. Note that row-security must also be enabled on the - table using <command>ALTER TABLE</command> in order for created policies - to be applied. + The <command>CREATE POLICY</command> command defines a new policy for a + table. Note that row level security must also be enabled on the table using + <command>ALTER TABLE</command> in order for created policies to be applied. </para> <para> - A row-security policy is an expression which is added to the security-barrier + A policy is an expression which is added to the security-barrier qualifications of queries which are run against the table the policy is on, or an expression which is added to the with-check options for a table and which is applied to rows which would be added to the table. @@ -49,7 +48,7 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable expression will be evaluated against the rows which are going to be added to the table. By adding policies to a table, a user can limit the rows which a given user can select, insert, update, or delete. This capability is also - known as Row-Level Security or RLS. + known as Row Level Security or RLS. </para> <para> @@ -66,22 +65,22 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable </para> <para> - Note that while row-security policies will be applied for explicit queries - against tables in the system, they are not applied when the system is - performing internal referential integrity checks or validating constraints. - This means there are indirect ways to determine that a given value exists. - An example of this is attempting to insert a duplicate value - into a column which is the primary key or has a unique constraint. If the - insert fails then the user can infer that the value already exists (this - example assumes that the user is permitted by policy to insert - records which they are not allowed to see). Another example is where a user - is allowed to insert into a table which references another, otherwise hidden - table. Existence can be determined by the user inserting values into the - referencing table, where success would indicate that the value exists in the - referenced table. These issues can be addressed by carefully crafting - policies which prevent users from being able to insert, delete, or update - records at all which might possibly indicate a value they are not otherwise - able to see, or by using generated values (e.g.: surrogate keys) instead. + Note that while policies will be applied for explicit queries against tables + in the system, they are not applied when the system is performing internal + referential integrity checks or validating constraints. This means there are + indirect ways to determine that a given value exists. An example of this is + attempting to insert a duplicate value into a column which is the primary key + or has a unique constraint. If the insert fails then the user can infer that + the value already exists (this example assumes that the user is permitted by + policy to insert records which they are not allowed to see). Another example + is where a user is allowed to insert into a table which references another, + otherwise hidden table. Existence can be determined by the user inserting + values into the referencing table, where success would indicate that the + value exists in the referenced table. These issues can be addressed by + carefully crafting policies which prevent users from being able to insert, + delete, or update records at all which might possibly indicate a value they + are not otherwise able to see, or by using generated values (e.g.: surrogate + keys) instead. </para> <para> @@ -291,8 +290,8 @@ CREATE POLICY <replaceable class="parameter">name</replaceable> ON <replaceable <para> In order to maintain <firstterm>referential integrity</firstterm> between - two related tables, row-security policies are not applied when the system - performs checks on foreign key constraints. + two related tables, policies are not applied when the system performs + checks on foreign key constraints. </para> </refsect1> diff --git a/doc/src/sgml/ref/drop_policy.sgml b/doc/src/sgml/ref/drop_policy.sgml index 31ca9db220eca6148a1fe5d7e0ebae94dd64e6c6..bd4ef5cf7ce03f80d5283b4dcf60fdae4b40d436 100644 --- a/doc/src/sgml/ref/drop_policy.sgml +++ b/doc/src/sgml/ref/drop_policy.sgml @@ -16,7 +16,7 @@ PostgreSQL documentation <refnamediv> <refname>DROP POLICY</refname> - <refpurpose>remove a row-security policy from a table</refpurpose> + <refpurpose>remove a policy from a table</refpurpose> </refnamediv> <refsynopsisdiv> @@ -29,11 +29,11 @@ DROP POLICY [ IF EXISTS ] <replaceable class="parameter">name</replaceable> ON < <title>Description</title> <para> - <command>DROP POLICY</command> removes the specified row-security policy - from the table. Note that if the last policy is removed for a table and - the table still has ROW POLICY enabled via <command>ALTER TABLE</command>, - then the default-deny policy will be used. <command>ALTER TABLE</command> - can be used to disable row security for a table using + <command>DROP POLICY</command> removes the specified policy from the table. + Note that if the last policy is removed for a table and the table still has + row level security enabled via <command>ALTER TABLE</command>, then the + default-deny policy will be used. <command>ALTER TABLE</command> can be used + to disable row level security for a table using <literal>DISABLE ROW SECURITY</literal>, whether policies for the table exist or not. </para> @@ -80,8 +80,8 @@ DROP POLICY [ IF EXISTS ] <replaceable class="parameter">name</replaceable> ON < <title>Examples</title> <para> - To drop the row-security policy called <literal>p1</literal> on the - table named <literal>my_table</literal>: + To drop the policy called <literal>p1</literal> on the table named + <literal>my_table</literal>: <programlisting> DROP POLICY p1 ON my_table; diff --git a/doc/src/sgml/rules.sgml b/doc/src/sgml/rules.sgml index 66b3cc9bf2f48d3140040f1f2650f70ac967a90b..973db7435bc58d395a60a18b11a1f6e483cc9bd2 100644 --- a/doc/src/sgml/rules.sgml +++ b/doc/src/sgml/rules.sgml @@ -2133,7 +2133,7 @@ SELECT * FROM phone_number WHERE tricky(person, phone); </para> <para> - When it is necessary for a view to provide row-level security, the + When it is necessary for a view to provide row level security, the <literal>security_barrier</literal> attribute should be applied to the view. This prevents maliciously-chosen functions and operators from being invoked on rows until after the view has done its work. For diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile index b257b02ff5c198d56d00dff9376ac6adf02fec7d..a403c643600b82201ff6e8f0f7e310db6054839a 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 f338acf827d6c7976829f6dfaac215250fcbd96d..8ba5123c101a51e0dde74a49971477c2640932de 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 b69b75bcc2e1e53b0f6f7bff51dd970fe075b88c..e261307e9d5fbce0943c2572505a5d45a09cc55a 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 a819952c75dec233d01a823925d0ce243e50e3e2..22b8ceef622603cd4eae9a334cc8305b9e3dad6a 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 83e8f891222a3137934557e4a5f67ce8d059f8ee..08abe141f4169f98d671fe22fc3be1151b48daa0 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) { @@ -1394,6 +1394,30 @@ BeginCopy(bool is_from, /* plan the query */ 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 1b8c94bcfdf91668a42eb317ac33c1ba8fd8c48e..6a3002f5268e33cf349fca2a4934b0916bad1aec 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 470db5705cc57fa7838fee543d2e3aafbb80444f..d3a59aa3567c3c42e588247caedb0829d209f3d1 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 10d230ef431c5deb96161938c3be763899203b3a..290c826a68040d10b2db7b3a1da2543df7f7a789 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 56294552e715c8bb1516b7055e2c9c0b19355dba..2333e1bed926bba45664496a2e91ae4444507719 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 a753b2070088fcff5aaf1d8e61b150f56a2ddd34..c499486f01652bf25fff0b47a2bb4611fd8ff5c0 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 c97355e8fda8bacf5245f3e958b04d82e7f5621e..25f30676f0258e32bfa34378a73dbfab624754e2 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 fb74d6bf1f41df08ce52b25622320e2710dc3aed..f752ecc16a58dc2a289198715e6965f98815ea89 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 e630d0b6d81fc0219f5ebf764155560006e9b2e7..4d3fbca5969d8e4e956b27e53d6e640234883acd 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 bd180e7e87ba941b30a02ddbbc5017533c7584b5..7e48958ae85cdd3d8dd0aacbe1b8ea523f2d1031 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 e7021509017dfd13ca6fb02d72da1a88dcd49157..ad983c7158b3ca7071be222fd661d777b0b90f99 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 66c358cdec9b841fb53d9b99885d628acf7ef384..6c232dcf9ae3cf3d58dd290c2dc6771661ef48bd 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 d85ea1bbd3ae8fa693807e289a547bfb1e7efeef..c537fe3236ced2a0256ca3cfae28ffed9470ce13 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 c80ef3c6f899ac01a04f3c97ea592fcdf381b91e..79244e5686512a0de81d8609e5cd5d7b5015503c 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) { diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c index 8bfc604eabbecb86edee5f0befebdbeb8325a081..1269ec3b28d9b371fec5d4a8d61215e393375785 100644 --- a/src/bin/pg_dump/common.c +++ b/src/bin/pg_dump/common.c @@ -248,8 +248,8 @@ getSchemaData(Archive *fout, DumpOptions *dopt, int *numTablesPtr) getRules(fout, &numRules); if (g_verbose) - write_msg(NULL, "reading row-security policies\n"); - getRowSecurity(fout, tblinfo, numTables); + write_msg(NULL, "reading policies\n"); + getPolicies(fout, tblinfo, numTables); *numTablesPtr = numTables; return tblinfo; diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c index 1a2ebcb1f48fb55e2c9899109e55aa64fb940cad..43065e84b2f267ff97f08d68a8a3ade3633e177b 100644 --- a/src/bin/pg_dump/pg_backup_archiver.c +++ b/src/bin/pg_dump/pg_backup_archiver.c @@ -3328,6 +3328,7 @@ _printTocEntry(ArchiveHandle *AH, TocEntry *te, RestoreOptions *ropt, bool isDat strcmp(te->desc, "RULE") == 0 || strcmp(te->desc, "TRIGGER") == 0 || strcmp(te->desc, "ROW SECURITY") == 0 || + strcmp(te->desc, "POLICY") == 0 || strcmp(te->desc, "USER MAPPING") == 0) { /* these object types don't have separate owners */ diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 69d359458bc878d3de546037bf5583a8c650d660..4175ddc823eb88bb93d2d3bf74f8b46f21ab63ff 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -233,7 +233,7 @@ static char *myFormatType(const char *typname, int32 typmod); static void getBlobs(Archive *fout); static void dumpBlob(Archive *fout, DumpOptions *dopt, BlobInfo *binfo); static int dumpBlobs(Archive *fout, DumpOptions *dopt, void *arg); -static void dumpRowSecurity(Archive *fout, DumpOptions *dopt, RowSecurityInfo *rsinfo); +static void dumpPolicy(Archive *fout, DumpOptions *dopt, PolicyInfo *polinfo); static void dumpDatabase(Archive *AH, DumpOptions *dopt); static void dumpEncoding(Archive *AH); static void dumpStdStrings(Archive *AH); @@ -2765,22 +2765,22 @@ dumpBlobs(Archive *fout, DumpOptions *dopt, void *arg) } /* - * getRowSecurity - * get information about every row-security policy on a dumpable table. + * getPolicies + * get information about policies on a dumpable table. */ void -getRowSecurity(Archive *fout, TableInfo tblinfo[], int numTables) +getPolicies(Archive *fout, TableInfo tblinfo[], int numTables) { PQExpBuffer query; PGresult *res; - RowSecurityInfo *rsinfo; + PolicyInfo *polinfo; int i_oid; int i_tableoid; - int i_rsecpolname; - int i_rseccmd; - int i_rsecroles; - int i_rsecqual; - int i_rsecwithcheck; + int i_polname; + int i_polcmd; + int i_polroles; + int i_polqual; + int i_polwithcheck; int i, j, ntups; @@ -2794,18 +2794,18 @@ getRowSecurity(Archive *fout, TableInfo tblinfo[], int numTables) { TableInfo *tbinfo = &tblinfo[i]; - /* Ignore row-security on tables not to be dumped */ + /* Ignore row security on tables not to be dumped */ if (!tbinfo->dobj.dump) continue; if (g_verbose) - write_msg(NULL, "reading row-security enabled for table \"%s\".\"%s\"\n", + write_msg(NULL, "reading row security enabled for table \"%s\".\"%s\"\n", tbinfo->dobj.namespace->dobj.name, tbinfo->dobj.name); /* - * Get row-security enabled information for the table. We represent - * RLS enabled on a table by creating RowSecurityInfo object with an + * Get row security enabled information for the table. We represent + * RLS enabled on a table by creating PolicyInfo object with an * empty policy. */ if (tbinfo->rowsec) @@ -2814,23 +2814,23 @@ getRowSecurity(Archive *fout, TableInfo tblinfo[], int numTables) * Note: use tableoid 0 so that this object won't be mistaken for * something that pg_depend entries apply to. */ - rsinfo = pg_malloc(sizeof(RowSecurityInfo)); - rsinfo->dobj.objType = DO_ROW_SECURITY; - rsinfo->dobj.catId.tableoid = 0; - rsinfo->dobj.catId.oid = tbinfo->dobj.catId.oid; - AssignDumpId(&rsinfo->dobj); - rsinfo->dobj.namespace = tbinfo->dobj.namespace; - rsinfo->dobj.name = pg_strdup(tbinfo->dobj.name); - rsinfo->rstable = tbinfo; - rsinfo->rsecpolname = NULL; - rsinfo->rseccmd = NULL; - rsinfo->rsecroles = NULL; - rsinfo->rsecqual = NULL; - rsinfo->rsecwithcheck = NULL; + polinfo = pg_malloc(sizeof(PolicyInfo)); + polinfo->dobj.objType = DO_POLICY; + polinfo->dobj.catId.tableoid = 0; + polinfo->dobj.catId.oid = tbinfo->dobj.catId.oid; + AssignDumpId(&polinfo->dobj); + polinfo->dobj.namespace = tbinfo->dobj.namespace; + polinfo->dobj.name = pg_strdup(tbinfo->dobj.name); + polinfo->poltable = tbinfo; + polinfo->polname = NULL; + polinfo->polcmd = NULL; + polinfo->polroles = NULL; + polinfo->polqual = NULL; + polinfo->polwithcheck = NULL; } if (g_verbose) - write_msg(NULL, "reading row-security policies for table \"%s\".\"%s\"\n", + write_msg(NULL, "reading policies for table \"%s\".\"%s\"\n", tbinfo->dobj.namespace->dobj.name, tbinfo->dobj.name); @@ -2843,13 +2843,13 @@ getRowSecurity(Archive *fout, TableInfo tblinfo[], int numTables) /* Get the policies for the table. */ appendPQExpBuffer(query, - "SELECT oid, tableoid, s.rsecpolname, s.rseccmd, " - "CASE WHEN s.rsecroles = '{0}' THEN 'PUBLIC' ELSE " - " array_to_string(ARRAY(SELECT rolname from pg_roles WHERE oid = ANY(s.rsecroles)), ', ') END AS rsecroles, " - "pg_get_expr(s.rsecqual, s.rsecrelid) AS rsecqual, " - "pg_get_expr(s.rsecwithcheck, s.rsecrelid) AS rsecwithcheck " - "FROM pg_catalog.pg_rowsecurity s " - "WHERE rsecrelid = '%u'", + "SELECT oid, tableoid, pol.polname, pol.polcmd, " + "CASE WHEN pol.polroles = '{0}' THEN 'PUBLIC' ELSE " + " array_to_string(ARRAY(SELECT rolname from pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, " + "pg_get_expr(pol.polqual, pol.polrelid) AS polqual, " + "pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck " + "FROM pg_catalog.pg_policy pol " + "WHERE polrelid = '%u'", tbinfo->dobj.catId.oid); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); @@ -2868,45 +2868,44 @@ getRowSecurity(Archive *fout, TableInfo tblinfo[], int numTables) i_oid = PQfnumber(res, "oid"); i_tableoid = PQfnumber(res, "tableoid"); - i_rsecpolname = PQfnumber(res, "rsecpolname"); - i_rseccmd = PQfnumber(res, "rseccmd"); - i_rsecroles = PQfnumber(res, "rsecroles"); - i_rsecqual = PQfnumber(res, "rsecqual"); - i_rsecwithcheck = PQfnumber(res, "rsecwithcheck"); + i_polname = PQfnumber(res, "polname"); + i_polcmd = PQfnumber(res, "polcmd"); + i_polroles = PQfnumber(res, "polroles"); + i_polqual = PQfnumber(res, "polqual"); + i_polwithcheck = PQfnumber(res, "polwithcheck"); - rsinfo = pg_malloc(ntups * sizeof(RowSecurityInfo)); + polinfo = pg_malloc(ntups * sizeof(PolicyInfo)); for (j = 0; j < ntups; j++) { - rsinfo[j].dobj.objType = DO_ROW_SECURITY; - rsinfo[j].dobj.catId.tableoid = + polinfo[j].dobj.objType = DO_POLICY; + polinfo[j].dobj.catId.tableoid = atooid(PQgetvalue(res, j, i_tableoid)); - rsinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid)); - AssignDumpId(&rsinfo[j].dobj); - rsinfo[j].dobj.namespace = tbinfo->dobj.namespace; - rsinfo[j].rstable = tbinfo; - rsinfo[j].rsecpolname = pg_strdup(PQgetvalue(res, j, - i_rsecpolname)); + polinfo[j].dobj.catId.oid = atooid(PQgetvalue(res, j, i_oid)); + AssignDumpId(&polinfo[j].dobj); + polinfo[j].dobj.namespace = tbinfo->dobj.namespace; + polinfo[j].poltable = tbinfo; + polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname)); - rsinfo[j].dobj.name = pg_strdup(rsinfo[j].rsecpolname); + polinfo[j].dobj.name = pg_strdup(polinfo[j].polname); - if (PQgetisnull(res, j, i_rseccmd)) - rsinfo[j].rseccmd = NULL; + if (PQgetisnull(res, j, i_polcmd)) + polinfo[j].polcmd = NULL; else - rsinfo[j].rseccmd = pg_strdup(PQgetvalue(res, j, i_rseccmd)); + polinfo[j].polcmd = pg_strdup(PQgetvalue(res, j, i_polcmd)); - rsinfo[j].rsecroles = pg_strdup(PQgetvalue(res, j, i_rsecroles)); + polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles)); - if (PQgetisnull(res, j, i_rsecqual)) - rsinfo[j].rsecqual = NULL; + if (PQgetisnull(res, j, i_polqual)) + polinfo[j].polqual = NULL; else - rsinfo[j].rsecqual = pg_strdup(PQgetvalue(res, j, i_rsecqual)); + polinfo[j].polqual = pg_strdup(PQgetvalue(res, j, i_polqual)); - if (PQgetisnull(res, j, i_rsecwithcheck)) - rsinfo[j].rsecwithcheck = NULL; + if (PQgetisnull(res, j, i_polwithcheck)) + polinfo[j].polwithcheck = NULL; else - rsinfo[j].rsecwithcheck - = pg_strdup(PQgetvalue(res, j, i_rsecwithcheck)); + polinfo[j].polwithcheck + = pg_strdup(PQgetvalue(res, j, i_polwithcheck)); } PQclear(res); } @@ -2914,13 +2913,13 @@ getRowSecurity(Archive *fout, TableInfo tblinfo[], int numTables) } /* - * dumpRowSecurity - * dump the definition of the given row-security policy + * dumpPolicy + * dump the definition of the given policy */ static void -dumpRowSecurity(Archive *fout, DumpOptions *dopt, RowSecurityInfo *rsinfo) +dumpPolicy(Archive *fout, DumpOptions *dopt, PolicyInfo *polinfo) { - TableInfo *tbinfo = rsinfo->rstable; + TableInfo *tbinfo = polinfo->poltable; PQExpBuffer query; PQExpBuffer delqry; const char *cmd; @@ -2929,23 +2928,23 @@ dumpRowSecurity(Archive *fout, DumpOptions *dopt, RowSecurityInfo *rsinfo) return; /* - * If rsecpolname is NULL, then this record is just indicating that ROW + * If polname is NULL, then this record is just indicating that ROW * LEVEL SECURITY is enabled for the table. Dump as ALTER TABLE <table> * ENABLE ROW LEVEL SECURITY. */ - if (rsinfo->rsecpolname == NULL) + if (polinfo->polname == NULL) { query = createPQExpBuffer(); appendPQExpBuffer(query, "ALTER TABLE %s ENABLE ROW LEVEL SECURITY;", - fmtId(rsinfo->dobj.name)); + fmtId(polinfo->dobj.name)); - ArchiveEntry(fout, rsinfo->dobj.catId, rsinfo->dobj.dumpId, - rsinfo->dobj.name, - rsinfo->dobj.namespace->dobj.name, + ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId, + polinfo->dobj.name, + polinfo->dobj.namespace->dobj.name, NULL, tbinfo->rolname, false, - "ROW SECURITY", SECTION_NONE, + "ROW SECURITY", SECTION_POST_DATA, query->data, "", NULL, NULL, 0, NULL, NULL); @@ -2954,19 +2953,19 @@ dumpRowSecurity(Archive *fout, DumpOptions *dopt, RowSecurityInfo *rsinfo) return; } - if (!rsinfo->rseccmd) + if (!polinfo->polcmd) cmd = "ALL"; - else if (strcmp(rsinfo->rseccmd, "r") == 0) + else if (strcmp(polinfo->polcmd, "r") == 0) cmd = "SELECT"; - else if (strcmp(rsinfo->rseccmd, "a") == 0) + else if (strcmp(polinfo->polcmd, "a") == 0) cmd = "INSERT"; - else if (strcmp(rsinfo->rseccmd, "w") == 0) + else if (strcmp(polinfo->polcmd, "w") == 0) cmd = "UPDATE"; - else if (strcmp(rsinfo->rseccmd, "d") == 0) + else if (strcmp(polinfo->polcmd, "d") == 0) cmd = "DELETE"; else { - write_msg(NULL, "unexpected command type: '%s'\n", rsinfo->rseccmd); + write_msg(NULL, "unexpected command type: '%s'\n", polinfo->polcmd); exit_nicely(1); } @@ -2974,28 +2973,28 @@ dumpRowSecurity(Archive *fout, DumpOptions *dopt, RowSecurityInfo *rsinfo) delqry = createPQExpBuffer(); appendPQExpBuffer(query, "CREATE POLICY %s ON %s FOR %s", - rsinfo->rsecpolname, fmtId(tbinfo->dobj.name), cmd); + polinfo->polname, fmtId(tbinfo->dobj.name), cmd); - if (rsinfo->rsecroles != NULL) - appendPQExpBuffer(query, " TO %s", rsinfo->rsecroles); + if (polinfo->polroles != NULL) + appendPQExpBuffer(query, " TO %s", polinfo->polroles); - if (rsinfo->rsecqual != NULL) - appendPQExpBuffer(query, " USING %s", rsinfo->rsecqual); + if (polinfo->polqual != NULL) + appendPQExpBuffer(query, " USING %s", polinfo->polqual); - if (rsinfo->rsecwithcheck != NULL) - appendPQExpBuffer(query, " WITH CHECK %s", rsinfo->rsecwithcheck); + if (polinfo->polwithcheck != NULL) + appendPQExpBuffer(query, " WITH CHECK %s", polinfo->polwithcheck); appendPQExpBuffer(query, ";\n"); appendPQExpBuffer(delqry, "DROP POLICY %s ON %s;\n", - rsinfo->rsecpolname, fmtId(tbinfo->dobj.name)); + polinfo->polname, fmtId(tbinfo->dobj.name)); - ArchiveEntry(fout, rsinfo->dobj.catId, rsinfo->dobj.dumpId, - rsinfo->dobj.name, - rsinfo->dobj.namespace->dobj.name, + ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId, + polinfo->dobj.name, + polinfo->dobj.namespace->dobj.name, NULL, tbinfo->rolname, false, - "ROW SECURITY", SECTION_POST_DATA, + "POLICY", SECTION_POST_DATA, query->data, delqry->data, NULL, NULL, 0, NULL, NULL); @@ -8232,8 +8231,8 @@ dumpDumpableObject(Archive *fout, DumpOptions *dopt, DumpableObject *dobj) NULL, 0, dumpBlobs, NULL); break; - case DO_ROW_SECURITY: - dumpRowSecurity(fout, dopt, (RowSecurityInfo *) dobj); + case DO_POLICY: + dumpPolicy(fout, dopt, (PolicyInfo *) dobj); break; case DO_PRE_DATA_BOUNDARY: case DO_POST_DATA_BOUNDARY: @@ -15631,7 +15630,7 @@ addBoundaryDependencies(DumpableObject **dobjs, int numObjs, case DO_TRIGGER: case DO_EVENT_TRIGGER: case DO_DEFAULT_ACL: - case DO_ROW_SECURITY: + case DO_POLICY: /* Post-data objects: must come after the post-data boundary */ addObjectDependency(dobj, postDataBound->dumpId); break; diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h index a7eb2fd9364b427ced713f531f88203fd279e906..d1d9ecbaa2d69fc773b4347e1b911188faa5df65 100644 --- a/src/bin/pg_dump/pg_dump.h +++ b/src/bin/pg_dump/pg_dump.h @@ -76,7 +76,7 @@ typedef enum DO_POST_DATA_BOUNDARY, DO_EVENT_TRIGGER, DO_REFRESH_MATVIEW, - DO_ROW_SECURITY + DO_POLICY } DumpableObjectType; typedef struct _dumpableObject @@ -210,7 +210,7 @@ typedef struct _tableInfo bool hasindex; /* does it have any indexes? */ bool hasrules; /* does it have any rules? */ bool hastriggers; /* does it have any triggers? */ - bool rowsec; /* is row-security enabled? */ + bool rowsec; /* is row security enabled? */ bool hasoids; /* does it have OIDs? */ uint32 frozenxid; /* for restore frozen xid */ uint32 minmxid; /* for restore min multi xid */ @@ -453,21 +453,21 @@ typedef struct _blobInfo } BlobInfo; /* - * The RowSecurityInfo struct is used to represent row policies on a table and + * The PolicyInfo struct is used to represent policies on a table and * to indicate if a table has RLS enabled (ENABLE ROW SECURITY). If - * rsecpolname is NULL, then the record indicates ENABLE ROW SECURITY, while if + * polname is NULL, then the record indicates ENABLE ROW SECURITY, while if * it's non-NULL then this is a regular policy definition. */ -typedef struct _rowSecurityInfo +typedef struct _policyInfo { DumpableObject dobj; - TableInfo *rstable; - char *rsecpolname; /* null indicates RLS is enabled on rel */ - char *rseccmd; - char *rsecroles; - char *rsecqual; - char *rsecwithcheck; -} RowSecurityInfo; + TableInfo *poltable; + char *polname; /* null indicates RLS is enabled on rel */ + char *polcmd; + char *polroles; + char *polqual; + char *polwithcheck; +} PolicyInfo; /* global decls */ extern bool force_quotes; /* double-quotes for identifiers flag */ @@ -549,6 +549,6 @@ extern DefaultACLInfo *getDefaultACLs(Archive *fout, DumpOptions *dopt, int *num extern void getExtensionMembership(Archive *fout, DumpOptions *dopt, ExtensionInfo extinfo[], int numExtensions); extern EventTriggerInfo *getEventTriggers(Archive *fout, int *numEventTriggers); -extern void getRowSecurity(Archive *fout, TableInfo tblinfo[], int numTables); +extern void getPolicies(Archive *fout, TableInfo tblinfo[], int numTables); #endif /* PG_DUMP_H */ diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c index 030bccc7e65a875ce7e0289707c77cdd2f513751..0e62af27765de642f1cfd4566e7ec16458f17c4c 100644 --- a/src/bin/pg_dump/pg_dump_sort.c +++ b/src/bin/pg_dump/pg_dump_sort.c @@ -28,8 +28,8 @@ static const char *modulename = gettext_noop("sorter"); * by OID. (This is a relatively crude hack to provide semi-reasonable * behavior for old databases without full dependency info.) Note: collations, * extensions, text search, foreign-data, materialized view, event trigger, - * and default ACL objects can't really happen here, so the rather bogus - * priorities for them don't matter. + * policies, and default ACL objects can't really happen here, so the rather + * bogus priorities for them don't matter. * * NOTE: object-type priorities must match the section assignments made in * pg_dump.c; that is, PRE_DATA objects must sort before DO_PRE_DATA_BOUNDARY, @@ -73,7 +73,7 @@ static const int oldObjectTypePriority[] = 13, /* DO_POST_DATA_BOUNDARY */ 20, /* DO_EVENT_TRIGGER */ 15, /* DO_REFRESH_MATVIEW */ - 21 /* DO_ROW_SECURITY */ + 21 /* DO_POLICY */ }; /* @@ -122,7 +122,7 @@ static const int newObjectTypePriority[] = 25, /* DO_POST_DATA_BOUNDARY */ 32, /* DO_EVENT_TRIGGER */ 33, /* DO_REFRESH_MATVIEW */ - 34 /* DO_ROW_SECURITY */ + 34 /* DO_POLICY */ }; static DumpId preDataBoundId; @@ -1438,9 +1438,9 @@ describeDumpableObject(DumpableObject *obj, char *buf, int bufsize) "BLOB DATA (ID %d)", obj->dumpId); return; - case DO_ROW_SECURITY: + case DO_POLICY: snprintf(buf, bufsize, - "ROW-SECURITY POLICY (ID %d OID %u)", + "POLICY (ID %d OID %u)", obj->dumpId, obj->catId.oid); return; case DO_PRE_DATA_BOUNDARY: diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c index a062fa871fafa42cb2d893ac6d159023fc2f9267..5a9ceca0df5e6ba1da3597d9a73b5f98582289d0 100644 --- a/src/bin/psql/describe.c +++ b/src/bin/psql/describe.c @@ -783,31 +783,31 @@ permissionsList(const char *pattern) if (pset.sversion >= 90500) appendPQExpBuffer(&buf, ",\n pg_catalog.array_to_string(ARRAY(\n" - " SELECT rsecpolname\n" - " || CASE WHEN rseccmd IS NOT NULL THEN\n" - " E' (' || rseccmd || E')'\n" + " SELECT polname\n" + " || CASE WHEN polcmd IS NOT NULL THEN\n" + " E' (' || polcmd || E')'\n" " ELSE E':' \n" " END\n" - " || CASE WHEN rs.rsecqual IS NOT NULL THEN\n" - " E'\\n (u): ' || pg_catalog.pg_get_expr(rsecqual, rsecrelid)\n" + " || CASE WHEN polqual IS NOT NULL THEN\n" + " E'\\n (u): ' || pg_catalog.pg_get_expr(polqual, polrelid)\n" " ELSE E''\n" " END\n" - " || CASE WHEN rsecwithcheck IS NOT NULL THEN\n" - " E'\\n (c): ' || pg_catalog.pg_get_expr(rsecwithcheck, rsecrelid)\n" + " || CASE WHEN polwithcheck IS NOT NULL THEN\n" + " E'\\n (c): ' || pg_catalog.pg_get_expr(polwithcheck, polrelid)\n" " ELSE E''\n" " END" - " || CASE WHEN rs.rsecroles <> '{0}' THEN\n" + " || CASE WHEN polroles <> '{0}' THEN\n" " E'\\n to: ' || pg_catalog.array_to_string(\n" " ARRAY(\n" " SELECT rolname\n" " FROM pg_catalog.pg_roles\n" - " WHERE oid = ANY (rs.rsecroles)\n" + " WHERE oid = ANY (polroles)\n" " ORDER BY 1\n" " ), E', ')\n" " ELSE E''\n" " END\n" - " FROM pg_catalog.pg_rowsecurity rs\n" - " WHERE rsecrelid = c.oid), E'\\n')\n" + " FROM pg_catalog.pg_policy pol\n" + " WHERE polrelid = c.oid), E'\\n')\n" " AS \"%s\"", gettext_noop("Policies")); @@ -2001,27 +2001,19 @@ describeOneTableDetails(const char *schemaname, /* print any row-level policies */ if (pset.sversion >= 90500) { - appendPQExpBuffer(&buf, - ",\n pg_catalog.pg_get_expr(rs.rsecqual, c.oid) as \"%s\"", - gettext_noop("Row-security")); - - if (verbose) - appendPQExpBuffer(&buf, - "\n LEFT JOIN pg_rowsecurity rs ON rs.rsecrelid = c.oid"); - printfPQExpBuffer(&buf, - "SELECT rs.rsecpolname,\n" - "CASE WHEN rs.rsecroles = '{0}' THEN NULL ELSE array_to_string(array(select rolname from pg_roles where oid = any (rs.rsecroles) order by 1),',') END,\n" - "pg_catalog.pg_get_expr(rs.rsecqual, rs.rsecrelid),\n" - "pg_catalog.pg_get_expr(rs.rsecwithcheck, rs.rsecrelid),\n" - "CASE rs.rseccmd \n" + "SELECT pol.polname,\n" + "CASE WHEN pol.polroles = '{0}' THEN NULL ELSE array_to_string(array(select rolname from pg_roles where oid = any (pol.polroles) order by 1),',') END,\n" + "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid),\n" + "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid),\n" + "CASE pol.polcmd \n" "WHEN 'r' THEN 'SELECT'\n" "WHEN 'u' THEN 'UPDATE'\n" "WHEN 'a' THEN 'INSERT'\n" "WHEN 'd' THEN 'DELETE'\n" "END AS cmd\n" - "FROM pg_catalog.pg_rowsecurity rs\n" - "WHERE rs.rsecrelid = '%s' ORDER BY 1;", + "FROM pg_catalog.pg_policy pol\n" + "WHERE pol.polrelid = '%s' ORDER BY 1;", oid); result = PSQLexec(buf.data); diff --git a/src/bin/psql/tab-complete.c b/src/bin/psql/tab-complete.c index 278d3952d4d0ad6e2c2d6707d96a715f9505fb44..1bb5a8373f3d1f18438f91f116ba73f99e7b1b6f 100644 --- a/src/bin/psql/tab-complete.c +++ b/src/bin/psql/tab-complete.c @@ -2069,7 +2069,7 @@ psql_completion(const char *text, int start, int end) static const char *const list_COMMENT[] = {"CAST", "COLLATION", "CONVERSION", "DATABASE", "EVENT TRIGGER", "EXTENSION", "FOREIGN DATA WRAPPER", "FOREIGN TABLE", - "SERVER", "INDEX", "LANGUAGE", "RULE", "SCHEMA", "SEQUENCE", + "SERVER", "INDEX", "LANGUAGE", "POLICY", "RULE", "SCHEMA", "SEQUENCE", "TABLE", "TYPE", "VIEW", "MATERIALIZED VIEW", "COLUMN", "AGGREGATE", "FUNCTION", "OPERATOR", "TRIGGER", "CONSTRAINT", "DOMAIN", "LARGE OBJECT", "TABLESPACE", "TEXT SEARCH", "ROLE", NULL}; diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index b670902b7d22eb24b97973b5bca43dcdbafe3030..a9290886252ad1b66ab83f025d544a39436ed3b8 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -53,6 +53,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 201411251 +#define CATALOG_VERSION_NO 201411271 #endif diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h index 6a4913a66e57f3d6f6d0705c6798370b50e168e3..87ac9240ae9e3a990691333db4ab8ffee51d0c74 100644 --- a/src/include/catalog/dependency.h +++ b/src/include/catalog/dependency.h @@ -147,7 +147,7 @@ typedef enum ObjectClass OCLASS_DEFACL, /* pg_default_acl */ OCLASS_EXTENSION, /* pg_extension */ OCLASS_EVENT_TRIGGER, /* pg_event_trigger */ - OCLASS_ROWSECURITY, /* pg_rowsecurity */ + OCLASS_POLICY, /* pg_policy */ MAX_OCLASS /* MUST BE LAST */ } ObjectClass; diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h index 870692cf54f9e5151ed116583dbf7fa6d713227f..bde1a848fee2b28502ca3b331aa8fe37eb229b68 100644 --- a/src/include/catalog/indexing.h +++ b/src/include/catalog/indexing.h @@ -299,11 +299,11 @@ DECLARE_UNIQUE_INDEX(pg_extension_name_index, 3081, on pg_extension using btree( DECLARE_UNIQUE_INDEX(pg_range_rngtypid_index, 3542, on pg_range using btree(rngtypid oid_ops)); #define RangeTypidIndexId 3542 -DECLARE_UNIQUE_INDEX(pg_rowsecurity_oid_index, 3257, on pg_rowsecurity using btree(oid oid_ops)); -#define RowSecurityOidIndexId 3257 +DECLARE_UNIQUE_INDEX(pg_policy_oid_index, 3257, on pg_policy using btree(oid oid_ops)); +#define PolicyOidIndexId 3257 -DECLARE_UNIQUE_INDEX(pg_rowsecurity_polname_relid_index, 3258, on pg_rowsecurity using btree(rsecrelid oid_ops, rsecpolname name_ops)); -#define RowSecurityRelidPolnameIndexId 3258 +DECLARE_UNIQUE_INDEX(pg_policy_polrelid_polname_index, 3258, on pg_policy using btree(polrelid oid_ops, polname name_ops)); +#define PolicyPolrelidPolnameIndexId 3258 /* last step of initialization script: build the indexes declared above */ BUILD_INDICES diff --git a/src/include/catalog/pg_class.h b/src/include/catalog/pg_class.h index 22c55a94903b63cfb30d11e56d2141de9889faa3..1054cd0500be3ce8c646ea3a463964850c538968 100644 --- a/src/include/catalog/pg_class.h +++ b/src/include/catalog/pg_class.h @@ -65,7 +65,7 @@ CATALOG(pg_class,1259) BKI_BOOTSTRAP BKI_ROWTYPE_OID(83) BKI_SCHEMA_MACRO bool relhasrules; /* has (or has had) any rules */ bool relhastriggers; /* has (or has had) any TRIGGERs */ bool relhassubclass; /* has (or has had) derived classes */ - bool relrowsecurity; /* row-security is enabled or not */ + bool relrowsecurity; /* row security is enabled or not */ bool relispopulated; /* matview currently holds query results */ char relreplident; /* see REPLICA_IDENTITY_xxx constants */ TransactionId relfrozenxid; /* all Xids < this are frozen in this rel */ diff --git a/src/include/catalog/pg_policy.h b/src/include/catalog/pg_policy.h new file mode 100644 index 0000000000000000000000000000000000000000..5d377a483899bc9ef1efffa69ad420becfc0eaf6 --- /dev/null +++ b/src/include/catalog/pg_policy.h @@ -0,0 +1,53 @@ +/* + * pg_policy.h + * definition of the system "policy" relation (pg_policy) + * + * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + */ +#ifndef PG_POLICY_H +#define PG_POLICY_H + +#include "catalog/genbki.h" + +/* ---------------- + * pg_policy definition. cpp turns this into + * typedef struct FormData_pg_policy + * ---------------- + */ +#define PolicyRelationId 3256 + +CATALOG(pg_policy,3256) +{ + NameData polname; /* Policy name. */ + Oid polrelid; /* Oid of the relation with policy. */ + char polcmd; /* One of ACL_*_CHR, or \0 for all */ + +#ifdef CATALOG_VARLEN + Oid polroles[1] /* Roles associated with policy, not-NULL */ + pg_node_tree polqual; /* Policy quals. */ + pg_node_tree polwithcheck; /* WITH CHECK quals. */ +#endif +} FormData_pg_policy; + +/* ---------------- + * Form_pg_policy corresponds to a pointer to a row with + * the format of pg_policy relation. + * ---------------- + */ +typedef FormData_pg_policy *Form_pg_policy; + +/* ---------------- + * compiler constants for pg_policy + * ---------------- + */ +#define Natts_pg_policy 6 +#define Anum_pg_policy_polname 1 +#define Anum_pg_policy_polrelid 2 +#define Anum_pg_policy_polcmd 3 +#define Anum_pg_policy_polroles 4 +#define Anum_pg_policy_polqual 5 +#define Anum_pg_policy_polwithcheck 6 + +#endif /* PG_POLICY_H */ diff --git a/src/include/catalog/pg_rowsecurity.h b/src/include/catalog/pg_rowsecurity.h deleted file mode 100644 index 2638d5e684894dbce672c21c38a99502076d0f1f..0000000000000000000000000000000000000000 --- a/src/include/catalog/pg_rowsecurity.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * pg_rowsecurity.h - * definition of the system catalog for row-security policy (pg_rowsecurity) - * - * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group - * Portions Copyright (c) 1994, Regents of the University of California - * - */ -#ifndef PG_ROWSECURITY_H -#define PG_ROWSECURITY_H - -#include "catalog/genbki.h" - -/* ---------------- - * pg_rowsecurity definition. cpp turns this into - * typedef struct FormData_pg_rowsecurity - * ---------------- - */ -#define RowSecurityRelationId 3256 - -CATALOG(pg_rowsecurity,3256) -{ - NameData rsecpolname; /* Policy name. */ - Oid rsecrelid; /* Oid of the relation with policy. */ - char rseccmd; /* One of ACL_*_CHR, or \0 for all */ - -#ifdef CATALOG_VARLEN - Oid rsecroles[1] /* Roles associated with policy, not-NULL */ - pg_node_tree rsecqual; /* Policy quals. */ - pg_node_tree rsecwithcheck; /* WITH CHECK quals. */ -#endif -} FormData_pg_rowsecurity; - -/* ---------------- - * Form_pg_rowsecurity corresponds to a pointer to a row with - * the format of pg_rowsecurity relation. - * ---------------- - */ -typedef FormData_pg_rowsecurity *Form_pg_rowsecurity; - -/* ---------------- - * compiler constants for pg_rowsecurity - * ---------------- - */ -#define Natts_pg_rowsecurity 6 -#define Anum_pg_rowsecurity_rsecpolname 1 -#define Anum_pg_rowsecurity_rsecrelid 2 -#define Anum_pg_rowsecurity_rseccmd 3 -#define Anum_pg_rowsecurity_rsecroles 4 -#define Anum_pg_rowsecurity_rsecqual 5 -#define Anum_pg_rowsecurity_rsecwithcheck 6 - -#endif /* PG_ROWSECURITY_H */ diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index 3e4f815852d5659a6d0e2bae77e4a8b4a98c6213..255415d93a3f50773a5aa24071c255d7d5a51406 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -121,7 +121,7 @@ typedef struct Query bool hasRecursive; /* WITH RECURSIVE was specified */ bool hasModifyingCTE; /* has INSERT/UPDATE/DELETE in WITH */ bool hasForUpdate; /* FOR [KEY] UPDATE/SHARE was specified */ - bool hasRowSecurity; /* Row-security policy is applied */ + bool hasRowSecurity; /* row security applied? */ List *cteList; /* WITH list (of CommonTableExpr's) */ diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 7f9eaf0df267d4cb1dad3cb86e06d78987bdb70e..48203a0d21faade68529a3cc217ce39f46a3b260 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -70,7 +70,7 @@ typedef struct PlannedStmt int nParamExec; /* number of PARAM_EXEC Params used */ - bool has_rls; /* row-security applied? */ + bool hasRowSecurity; /* row security applied? */ } PlannedStmt; diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h index 810b9c8893b077b5cc2d3689c4612d5b86b071b0..711649687ae8f4cd404d0a85b9cb6d311da8c82c 100644 --- a/src/include/nodes/relation.h +++ b/src/include/nodes/relation.h @@ -101,7 +101,7 @@ typedef struct PlannerGlobal bool transientPlan; /* redo plan when TransactionXmin changes? */ - bool has_rls; /* row-security is applied? */ + bool hasRowSecurity; /* row security applied? */ } PlannerGlobal; diff --git a/src/include/rewrite/rowsecurity.h b/src/include/rewrite/rowsecurity.h index 8b4d5c0918faacb236a1cc6b1f3d70edebf14f60..4144b25fec75cf4dc440a3ba077d4195f8d5a649 100644 --- a/src/include/rewrite/rowsecurity.h +++ b/src/include/rewrite/rowsecurity.h @@ -19,7 +19,7 @@ typedef struct RowSecurityPolicy { - Oid rsecid; /* OID of the policy */ + Oid policy_id; /* OID of the policy */ char *policy_name; /* Name of the policy */ char cmd; /* Type of command policy is for */ ArrayType *roles; /* Array of roles policy is for */ @@ -30,8 +30,8 @@ typedef struct RowSecurityPolicy typedef struct RowSecurityDesc { - MemoryContext rscxt; /* row-security memory context */ - List *policies; /* list of row-security policies */ + MemoryContext rscxt; /* row security memory context */ + List *policies; /* list of row security policies */ } RowSecurityDesc; /* GUC variable */ diff --git a/src/include/utils/plancache.h b/src/include/utils/plancache.h index 2622ceb54bc1908c4146d4332c631a530a048c54..9e1c0000aab06bd87c25b0475c704094b9460d1e 100644 --- a/src/include/utils/plancache.h +++ b/src/include/utils/plancache.h @@ -109,9 +109,9 @@ typedef struct CachedPlanSource double generic_cost; /* cost of generic plan, or -1 if not known */ double total_custom_cost; /* total cost of custom plans so far */ int num_custom_plans; /* number of plans included in total */ - bool has_rls; /* planned with row-security? */ + bool hasRowSecurity; /* planned with row security? */ int row_security_env; /* row security setting when planned */ - bool rowSecurityDisabled; /* is row-security disabled? */ + bool rowSecurityDisabled; /* is row security disabled? */ } CachedPlanSource; /* diff --git a/src/include/utils/rel.h b/src/include/utils/rel.h index 01a9ef32ebf9158815a67fae3b4f599654c9137b..48ebf5949430cc77690e1d73de6fb84de2b74613 100644 --- a/src/include/utils/rel.h +++ b/src/include/utils/rel.h @@ -106,7 +106,7 @@ typedef struct RelationData MemoryContext rd_rulescxt; /* private memory cxt for rd_rules, if any */ TriggerDesc *trigdesc; /* Trigger info, or NULL if rel has none */ /* use "struct" here to avoid needing to include rowsecurity.h: */ - struct RowSecurityDesc *rd_rsdesc; /* Row-security policies, or NULL */ + struct RowSecurityDesc *rd_rsdesc; /* row security policies, or NULL */ /* data managed by RelationGetIndexList: */ List *rd_indexlist; /* list of OIDs of indexes on relation */ diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out index 376292ac2effc0990f2effc58b8ed75405d76ad0..5eb61c46aa2afedd8521372c041890cdb20ffc12 100644 --- a/src/test/regress/expected/rowsecurity.out +++ b/src/test/regress/expected/rowsecurity.out @@ -173,7 +173,7 @@ EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dt Index Cond: (pguser = "current_user"()) (11 rows) --- only owner can change row-level security +-- only owner can change policies ALTER POLICY p1 ON document USING (true); --fail ERROR: must be owner of relation document DROP POLICY p1 ON document; --fail @@ -724,7 +724,7 @@ CREATE TABLE dependent (x integer, y integer); CREATE POLICY d1 ON dependent FOR ALL TO PUBLIC USING (x = (SELECT d.x FROM dependee d WHERE d.y = y)); -DROP TABLE dependee; -- Should fail without CASCADE due to dependency on row-security qual? +DROP TABLE dependee; -- Should fail without CASCADE due to dependency on row security qual? ERROR: cannot drop table dependee because other objects depend on it DETAIL: policy d1 on table dependent depends on table dependee HINT: Use DROP ... CASCADE to drop the dependent objects too. @@ -746,7 +746,7 @@ CREATE POLICY r1 ON rec1 USING (x = (SELECT r.x FROM rec1 r WHERE y = r.y)); ALTER TABLE rec1 ENABLE ROW LEVEL SECURITY; SET SESSION AUTHORIZATION rls_regress_user1; SELECT * FROM rec1; -- fail, direct recursion -ERROR: infinite recursion detected in row-security policy for relation "rec1" +ERROR: infinite recursion detected in policy for relation "rec1" -- -- Mutual recursion -- @@ -757,7 +757,7 @@ CREATE POLICY r2 ON rec2 USING (a = (SELECT x FROM rec1 WHERE y = b)); ALTER TABLE rec2 ENABLE ROW LEVEL SECURITY; SET SESSION AUTHORIZATION rls_regress_user1; SELECT * FROM rec1; -- fail, mutual recursion -ERROR: infinite recursion detected in row-security policy for relation "rec1" +ERROR: infinite recursion detected in policy for relation "rec1" -- -- Mutual recursion via views -- @@ -769,7 +769,7 @@ ALTER POLICY r1 ON rec1 USING (x = (SELECT a FROM rec2v WHERE b = y)); ALTER POLICY r2 ON rec2 USING (a = (SELECT x FROM rec1v WHERE y = b)); SET SESSION AUTHORIZATION rls_regress_user1; SELECT * FROM rec1; -- fail, mutual recursion via views -ERROR: infinite recursion detected in row-security policy for relation "rec1" +ERROR: infinite recursion detected in policy for relation "rec1" -- -- Mutual recursion via .s.b views -- @@ -785,7 +785,7 @@ CREATE POLICY r1 ON rec1 USING (x = (SELECT a FROM rec2v WHERE b = y)); CREATE POLICY r2 ON rec2 USING (a = (SELECT x FROM rec1v WHERE y = b)); SET SESSION AUTHORIZATION rls_regress_user1; SELECT * FROM rec1; -- fail, mutual recursion via s.b. views -ERROR: infinite recursion detected in row-security policy for relation "rec1" +ERROR: infinite recursion detected in policy for relation "rec1" -- -- recursive RLS and VIEWs in policy -- @@ -803,9 +803,9 @@ ALTER TABLE s2 ENABLE ROW LEVEL SECURITY; SET SESSION AUTHORIZATION rls_regress_user1; CREATE VIEW v2 AS SELECT * FROM s2 WHERE y like '%af%'; SELECT * FROM s1 WHERE f_leak(b); -- fail (infinite recursion) -ERROR: infinite recursion detected in row-security policy for relation "s1" +ERROR: infinite recursion detected in policy for relation "s1" INSERT INTO s1 VALUES (1, 'foo'); -- fail (infinite recursion) -ERROR: infinite recursion detected in row-security policy for relation "s1" +ERROR: infinite recursion detected in policy for relation "s1" SET SESSION AUTHORIZATION rls_regress_user0; DROP POLICY p3 on s1; ALTER POLICY p2 ON s2 USING (x % 2 = 0); @@ -897,7 +897,7 @@ SET SESSION AUTHORIZATION rls_regress_user0; ALTER POLICY p2 ON s2 USING (x in (select a from s1 where b like '%d2%')); SET SESSION AUTHORIZATION rls_regress_user1; SELECT * FROM s1 WHERE f_leak(b); -- fail (infinite recursion via view) -ERROR: infinite recursion detected in row-security policy for relation "s1" +ERROR: infinite recursion detected in policy for relation "s1" -- prepared statement with rls_regress_user0 privilege PREPARE p1(int) AS SELECT * FROM t1 WHERE a <= $1; EXECUTE p1(2); @@ -1714,24 +1714,24 @@ WITH cte1 AS (INSERT INTO t1 VALUES (20, 'Success') RETURNING *) SELECT * FROM c -- RESET SESSION AUTHORIZATION; ALTER POLICY p1 ON t1 RENAME TO p1; --fail -ERROR: row-policy "p1" for table "t1" already exists -SELECT rsecpolname, relname - FROM pg_rowsecurity rs - JOIN pg_class pc ON (pc.oid = rs.rsecrelid) +ERROR: policy "p1" for table "t1" already exists +SELECT polname, relname + FROM pg_policy pol + JOIN pg_class pc ON (pc.oid = pol.polrelid) WHERE relname = 't1'; - rsecpolname | relname --------------+--------- - p1 | t1 + polname | relname +---------+--------- + p1 | t1 (1 row) ALTER POLICY p1 ON t1 RENAME TO p2; --ok -SELECT rsecpolname, relname - FROM pg_rowsecurity rs - JOIN pg_class pc ON (pc.oid = rs.rsecrelid) +SELECT polname, relname + FROM pg_policy pol + JOIN pg_class pc ON (pc.oid = pol.polrelid) WHERE relname = 't1'; - rsecpolname | relname --------------+--------- - p2 | t1 + polname | relname +---------+--------- + p2 | t1 (1 row) -- @@ -2161,7 +2161,7 @@ SET row_security TO ON; COPY copy_t FROM STDIN; --ok SET row_security TO FORCE; COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS. -ERROR: COPY FROM not supported with row security. +ERROR: COPY FROM not supported with row level security. HINT: Use direct INSERT statements instead. -- Check COPY FROM as user with permissions. SET SESSION AUTHORIZATION rls_regress_user1; @@ -2170,11 +2170,11 @@ COPY copy_t FROM STDIN; --fail - insufficient privilege to bypass rls. ERROR: insufficient privilege to bypass row security. SET row_security TO ON; COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS. -ERROR: COPY FROM not supported with row security. +ERROR: COPY FROM not supported with row level security. HINT: Use direct INSERT statements instead. SET row_security TO FORCE; COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS. -ERROR: COPY FROM not supported with row security. +ERROR: COPY FROM not supported with row level security. HINT: Use direct INSERT statements instead. -- Check COPY TO as user with permissions and BYPASSRLS SET SESSION AUTHORIZATION rls_regress_exempt_user; @@ -2182,11 +2182,11 @@ SET row_security TO OFF; COPY copy_t FROM STDIN; --ok SET row_security TO ON; COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS. -ERROR: COPY FROM not supported with row security. +ERROR: COPY FROM not supported with row level security. HINT: Use direct INSERT statements instead. SET row_security TO FORCE; COPY copy_t FROM STDIN; --fail - COPY FROM not supported by RLS. -ERROR: COPY FROM not supported with row security. +ERROR: COPY FROM not supported with row level security. HINT: Use direct INSERT statements instead. -- Check COPY FROM as user without permissions. SET SESSION AUTHORIZATION rls_regress_user2; diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out index c79b45c53a0fd2f233a6b389056532b4308445cd..80c3351291638cc8f37194f34e0eb773564616ca 100644 --- a/src/test/regress/expected/rules.out +++ b/src/test/regress/expected/rules.out @@ -1355,18 +1355,18 @@ pg_matviews| SELECT n.nspname AS schemaname, WHERE (c.relkind = 'm'::"char"); pg_policies| SELECT n.nspname AS schemaname, c.relname AS tablename, - rs.rsecpolname AS policyname, + pol.polname AS policyname, CASE - WHEN (rs.rsecroles = '{0}'::oid[]) THEN (string_to_array('public'::text, ''::text))::name[] + WHEN (pol.polroles = '{0}'::oid[]) THEN (string_to_array('public'::text, ''::text))::name[] ELSE ARRAY( SELECT pg_authid.rolname FROM pg_authid - WHERE (pg_authid.oid = ANY (rs.rsecroles)) + WHERE (pg_authid.oid = ANY (pol.polroles)) ORDER BY pg_authid.rolname) END AS roles, CASE - WHEN (rs.rseccmd IS NULL) THEN 'ALL'::text + WHEN (pol.polcmd IS NULL) THEN 'ALL'::text ELSE - CASE rs.rseccmd + CASE pol.polcmd WHEN 'r'::"char" THEN 'SELECT'::text WHEN 'a'::"char" THEN 'INSERT'::text WHEN 'u'::"char" THEN 'UPDATE'::text @@ -1374,10 +1374,10 @@ pg_policies| SELECT n.nspname AS schemaname, ELSE NULL::text END END AS cmd, - pg_get_expr(rs.rsecqual, rs.rsecrelid) AS qual, - pg_get_expr(rs.rsecwithcheck, rs.rsecrelid) AS with_check - FROM ((pg_rowsecurity rs - JOIN pg_class c ON ((c.oid = rs.rsecrelid))) + pg_get_expr(pol.polqual, pol.polrelid) AS qual, + pg_get_expr(pol.polwithcheck, pol.polrelid) AS with_check + FROM ((pg_policy pol + JOIN pg_class c ON ((c.oid = pol.polrelid))) LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace))); pg_prepared_statements| SELECT p.name, p.statement, diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out index 2c8ec118a754ccc296720f446b7069daf5daa638..c7be273ae166146fbd44a8f1afc5ba7f89e42f3e 100644 --- a/src/test/regress/expected/sanity_check.out +++ b/src/test/regress/expected/sanity_check.out @@ -118,10 +118,10 @@ pg_opclass|t pg_operator|t pg_opfamily|t pg_pltemplate|t +pg_policy|t pg_proc|t pg_range|t pg_rewrite|t -pg_rowsecurity|t pg_seclabel|t pg_shdepend|t pg_shdescription|t diff --git a/src/test/regress/sql/rowsecurity.sql b/src/test/regress/sql/rowsecurity.sql index 2d5ddb4b8328b891b24018b003f267dc35e6da6b..181043f416489dccea0ec51930f0c89928691638 100644 --- a/src/test/regress/sql/rowsecurity.sql +++ b/src/test/regress/sql/rowsecurity.sql @@ -102,7 +102,7 @@ SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle) ORDER BY did; EXPLAIN (COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle); EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle); --- only owner can change row-level security +-- only owner can change policies ALTER POLICY p1 ON document USING (true); --fail DROP POLICY p1 ON document; --fail @@ -274,7 +274,7 @@ CREATE POLICY d1 ON dependent FOR ALL TO PUBLIC USING (x = (SELECT d.x FROM dependee d WHERE d.y = y)); -DROP TABLE dependee; -- Should fail without CASCADE due to dependency on row-security qual? +DROP TABLE dependee; -- Should fail without CASCADE due to dependency on row security qual? DROP TABLE dependee CASCADE; @@ -659,16 +659,16 @@ WITH cte1 AS (INSERT INTO t1 VALUES (20, 'Success') RETURNING *) SELECT * FROM c RESET SESSION AUTHORIZATION; ALTER POLICY p1 ON t1 RENAME TO p1; --fail -SELECT rsecpolname, relname - FROM pg_rowsecurity rs - JOIN pg_class pc ON (pc.oid = rs.rsecrelid) +SELECT polname, relname + FROM pg_policy pol + JOIN pg_class pc ON (pc.oid = pol.polrelid) WHERE relname = 't1'; ALTER POLICY p1 ON t1 RENAME TO p2; --ok -SELECT rsecpolname, relname - FROM pg_rowsecurity rs - JOIN pg_class pc ON (pc.oid = rs.rsecrelid) +SELECT polname, relname + FROM pg_policy pol + JOIN pg_class pc ON (pc.oid = pol.polrelid) WHERE relname = 't1'; --