<entry>template data for procedural languages</entry>
</row>
+ <row>
+ <entry><link linkend="catalog-pg-policy"><structname>pg_policy</structname></link></entry>
+ <entry>row-security policies</entry>
+ </row>
+
<row>
<entry><link linkend="catalog-pg-proc"><structname>pg_proc</structname></link></entry>
<entry>functions and procedures</entry>
<entry>replication slot information</entry>
</row>
- <row>
- <entry><link linkend="catalog-pg-policy"><structname>pg_policy</structname></link></entry>
- <entry>table policies</entry>
- </row>
-
<row>
<entry><link linkend="catalog-pg-seclabel"><structname>pg_seclabel</structname></link></entry>
<entry>security labels on database objects</entry>
</row>
<row>
- <entry><structfield>relrowsecurity</structfield></entry>
+ <entry><structfield>relhassubclass</structfield></entry>
<entry><type>bool</type></entry>
<entry></entry>
- <entry>
- True if table has row level security enabled; see
- <link linkend="catalog-pg-policy"><structname>pg_policy</structname></link> catalog
- </entry>
+ <entry>True if table has (or once had) any inheritance children</entry>
</row>
<row>
- <entry><structfield>relhassubclass</structfield></entry>
+ <entry><structfield>relrowsecurity</structfield></entry>
<entry><type>bool</type></entry>
<entry></entry>
- <entry>True if table has (or once had) any inheritance children</entry>
+ <entry>
+ True if table has row-level security enabled; see
+ <link linkend="catalog-pg-policy"><structname>pg_policy</structname></link> catalog
+ </entry>
</row>
<row>
</sect1>
+ <sect1 id="catalog-pg-policy">
+ <title><structname>pg_policy</structname></title>
+
+ <indexterm zone="catalog-pg-policy">
+ <primary>pg_policy</primary>
+ </indexterm>
+
+ <para>
+ The catalog <structname>pg_policy</structname> stores row-level
+ security policies for tables. A policy includes the kind of
+ command that it applies to (possibly all commands), the roles that it
+ applies to, the expression to be added as a security-barrier
+ qualification to queries that include the table, and the expression
+ to be added as a <literal>WITH CHECK</> option for queries that attempt to
+ add new records to the table.
+ </para>
+
+ <table>
+
+ <title><structname>pg_policy</structname> Columns</title>
+
+ <tgroup cols="4">
+ <thead>
+ <row>
+ <entry>Name</entry>
+ <entry>Type</entry>
+ <entry>References</entry>
+ <entry>Description</entry>
+ </row>
+ </thead>
+
+ <tbody>
+ <row>
+ <entry><structfield>polname</structfield></entry>
+ <entry><type>name</type></entry>
+ <entry></entry>
+ <entry>The name of the policy</entry>
+ </row>
+
+ <row>
+ <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 policy applies</entry>
+ </row>
+
+ <row>
+ <entry><structfield>polcmd</structfield></entry>
+ <entry><type>char</type></entry>
+ <entry></entry>
+ <entry>The command type to which the policy is applied:
+ <literal>r</> for <command>SELECT</>,
+ <literal>a</> for <command>INSERT</>,
+ <literal>w</> for <command>UPDATE</>,
+ <literal>d</> for <command>DELETE</>,
+ or <literal>*</> for all</entry>
+ </row>
+
+ <row>
+ <entry><structfield>polroles</structfield></entry>
+ <entry><type>oid[]</type></entry>
+ <entry><literal><link linkend="catalog-pg-authid"><structname>pg_authid</structname></link>.oid</literal></entry>
+ <entry>The roles to which the policy is applied</entry>
+ </row>
+
+ <row>
+ <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 that use the table</entry>
+ </row>
+
+ <row>
+ <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 that attempt to add rows to the table</entry>
+ </row>
+
+ </tbody>
+ </tgroup>
+ </table>
+
+ <note>
+ <para>
+ Policies stored in <structname>pg_policy</> are applied only when
+ <structname>pg_class</>.<structfield>relrowsecurity</> is set for
+ their table.
+ </para>
+ </note>
+
+ </sect1>
<sect1 id="catalog-pg-proc">
<title><structname>pg_proc</structname></title>
</table>
</sect1>
- <sect1 id="catalog-pg-policy">
- <title><structname>pg_policy</structname></title>
-
- <indexterm zone="catalog-pg-policy">
- <primary>pg_policy</primary>
- </indexterm>
-
- <para>
- 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
- qualification to queries which include the table and the expression
- to be added as a with-check option for queries which attempt to add
- new records to the table.
- </para>
-
- <table>
-
- <title><structname>pg_policy</structname> Columns</title>
-
- <tgroup cols="4">
- <thead>
- <row>
- <entry>Name</entry>
- <entry>Type</entry>
- <entry>References</entry>
- <entry>Description</entry>
- </row>
- </thead>
-
- <tbody>
- <row>
- <entry><structfield>polname</structfield></entry>
- <entry><type>name</type></entry>
- <entry></entry>
- <entry>The name of the policy</entry>
- </row>
-
- <row>
- <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 policy belongs</entry>
- </row>
-
- <row>
- <entry><structfield>polcmd</structfield></entry>
- <entry><type>char</type></entry>
- <entry></entry>
- <entry>The command type to which the policy is applied.</entry>
- </row>
-
- <row>
- <entry><structfield>polroles</structfield></entry>
- <entry><type>char</type></entry>
- <entry></entry>
- <entry>The roles to which the policy is applied.</entry>
- </row>
-
- <row>
- <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>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>
- </row>
-
- </tbody>
- </tgroup>
- </table>
-
- <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.
- </para>
- </note>
-
- </sect1>
-
<sect1 id="catalog-pg-seclabel">
<title><structname>pg_seclabel</structname></title>
<para>
The view <structname>pg_policies</structname> provides access to
- useful information about each policy in the database.
+ useful information about each row-level security policy in the database.
</para>
<table>
<row>
<entry><structfield>policyname</structfield></entry>
<entry><type>name</type></entry>
- <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.relname</literal></entry>
+ <entry><literal><link linkend="catalog-pg-policy"><structname>pg_policy</structname></link>.polname</literal></entry>
<entry>Name of policy</entry>
</row>
<row>
- <entry><structfield>cmd</structfield></entry>
- <entry><type>text</type></entry>
+ <entry><structfield>roles</structfield></entry>
+ <entry><type>name[]</type></entry>
<entry></entry>
- <entry>The command type to which the policy is applied.</entry>
+ <entry>The roles to which this policy applies</entry>
</row>
<row>
- <entry><structfield>roles</structfield></entry>
- <entry><type>name[]</type></entry>
+ <entry><structfield>cmd</structfield></entry>
+ <entry><type>text</type></entry>
<entry></entry>
- <entry>The roles to which this policy applies.</entry>
+ <entry>The command type to which the policy is applied</entry>
</row>
<row>
<entry><structfield>qual</structfield></entry>
<entry><type>text</type></entry>
<entry></entry>
<entry>The expression added to the security barrier qualifications for
- queries which this policy applies to.</entry>
+ queries that this policy applies to</entry>
</row>
<row>
<entry><structfield>with_check</structfield></entry>
<entry><type>text</type></entry>
<entry></entry>
- <entry>The expression added to the with check qualifications for
- queries which attempt to add rows to this table.</entry>
+ <entry>The expression added to the WITH CHECK qualifications for
+ queries that attempt to add rows to this table</entry>
</row>
</tbody>
</tgroup>
WHERE oid = ANY (pol.polroles) ORDER BY 1
)
END AS roles,
- 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
+ CASE pol.polcmd
+ WHEN 'r' THEN 'SELECT'
+ WHEN 'a' THEN 'INSERT'
+ WHEN 'w' THEN 'UPDATE'
+ WHEN 'd' THEN 'DELETE'
+ WHEN '*' THEN 'ALL'
END AS cmd,
pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS qual,
pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS with_check
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/pg_list.h"
-#include "optimizer/clauses.h"
#include "parser/parse_clause.h"
#include "parser/parse_node.h"
#include "parser/parse_relation.h"
+#include "rewrite/rewriteManip.h"
#include "rewrite/rowsecurity.h"
#include "storage/lock.h"
#include "utils/acl.h"
char cmd;
if (!cmd_name)
- elog(ERROR, "unrecognized command");
+ elog(ERROR, "unrecognized policy command");
if (strcmp(cmd_name, "all") == 0)
- cmd = 0;
+ cmd = '*';
else if (strcmp(cmd_name, "select") == 0)
cmd = ACL_SELECT_CHR;
else if (strcmp(cmd_name, "insert") == 0)
else if (strcmp(cmd_name, "delete") == 0)
cmd = ACL_DELETE_CHR;
else
- elog(ERROR, "unrecognized command");
+ elog(ERROR, "unrecognized policy command");
return cmd;
}
}
/*
- * Load row security policy from the catalog, and keep it in
- * the relation cache.
+ * Load row security policy from the catalog, and store it in
+ * the relation's relcache entry.
+ *
+ * We will always set up some kind of policy here. If no explicit policies
+ * are found then an implicit default-deny policy is created.
*/
void
RelationBuildRowSecurity(Relation relation)
{
- Relation catalog;
- ScanKeyData skey;
- SysScanDesc sscan;
- HeapTuple tuple;
- MemoryContext oldcxt;
- MemoryContext rscxt = NULL;
- RowSecurityDesc *rsdesc = NULL;
-
- catalog = heap_open(PolicyRelationId, AccessShareLock);
+ MemoryContext rscxt;
+ MemoryContext oldcxt = CurrentMemoryContext;
+ RowSecurityDesc * volatile rsdesc = NULL;
- ScanKeyInit(&skey,
- Anum_pg_policy_polrelid,
- BTEqualStrategyNumber, F_OIDEQ,
- ObjectIdGetDatum(RelationGetRelid(relation)));
+ /*
+ * Create a memory context to hold everything associated with this
+ * relation's row security policy. This makes it easy to clean up
+ * during a relcache flush.
+ */
+ rscxt = AllocSetContextCreate(CacheMemoryContext,
+ "row security descriptor",
+ ALLOCSET_SMALL_MINSIZE,
+ ALLOCSET_SMALL_INITSIZE,
+ ALLOCSET_SMALL_MAXSIZE);
- sscan = systable_beginscan(catalog, PolicyPolrelidPolnameIndexId, true,
- NULL, 1, &skey);
+ /*
+ * Since rscxt lives under CacheMemoryContext, it is long-lived. Use
+ * a PG_TRY block to ensure it'll get freed if we fail partway through.
+ */
PG_TRY();
{
- /*
- * Set up our memory context- we will always set up some kind of
- * policy here. If no explicit policies are found then an implicit
- * default-deny policy is created.
- */
- rscxt = AllocSetContextCreate(CacheMemoryContext,
- "row security descriptor",
- ALLOCSET_SMALL_MINSIZE,
- ALLOCSET_SMALL_INITSIZE,
- ALLOCSET_SMALL_MAXSIZE);
+ Relation catalog;
+ ScanKeyData skey;
+ SysScanDesc sscan;
+ HeapTuple tuple;
+
rsdesc = MemoryContextAllocZero(rscxt, sizeof(RowSecurityDesc));
rsdesc->rscxt = rscxt;
+ catalog = heap_open(PolicyRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey,
+ Anum_pg_policy_polrelid,
+ BTEqualStrategyNumber, F_OIDEQ,
+ ObjectIdGetDatum(RelationGetRelid(relation)));
+
+ sscan = systable_beginscan(catalog, PolicyPolrelidPolnameIndexId, true,
+ NULL, 1, &skey);
+
/*
* Loop through the row level security policies for this relation, if
* any.
{
Datum value_datum;
char cmd_value;
- ArrayType *roles;
+ Datum roles_datum;
char *qual_value;
Expr *qual_expr;
char *with_check_value;
char *policy_name_value;
Oid policy_id;
bool isnull;
- RowSecurityPolicy *policy = NULL;
+ RowSecurityPolicy *policy;
- oldcxt = MemoryContextSwitchTo(rscxt);
+ /*
+ * Note: all the pass-by-reference data we collect here is either
+ * still stored in the tuple, or constructed in the caller's
+ * short-lived memory context. We must copy it into rscxt
+ * explicitly below.
+ */
/* Get policy command */
value_datum = heap_getattr(tuple, Anum_pg_policy_polcmd,
RelationGetDescr(catalog), &isnull);
- if (isnull)
- cmd_value = 0;
- else
- cmd_value = DatumGetChar(value_datum);
+ Assert(!isnull);
+ cmd_value = DatumGetChar(value_datum);
/* Get policy name */
value_datum = heap_getattr(tuple, Anum_pg_policy_polname,
RelationGetDescr(catalog), &isnull);
Assert(!isnull);
- policy_name_value = DatumGetCString(value_datum);
+ policy_name_value = NameStr(*(DatumGetName(value_datum)));
/* Get policy roles */
- value_datum = heap_getattr(tuple, Anum_pg_policy_polroles,
+ roles_datum = heap_getattr(tuple, Anum_pg_policy_polroles,
RelationGetDescr(catalog), &isnull);
- Assert(!isnull);
- roles = DatumGetArrayTypeP(value_datum);
+ /* shouldn't be null, but initdb doesn't mark it so, so check */
+ if (isnull)
+ elog(ERROR, "unexpected null value in pg_policy.polroles");
/* Get policy qual */
value_datum = heap_getattr(tuple, Anum_pg_policy_polqual,
/* Get WITH CHECK qual */
value_datum = heap_getattr(tuple, Anum_pg_policy_polwithcheck,
RelationGetDescr(catalog), &isnull);
-
if (!isnull)
{
with_check_value = TextDatumGetCString(value_datum);
policy_id = HeapTupleGetOid(tuple);
+ /* Now copy everything into the cache context */
+ MemoryContextSwitchTo(rscxt);
+
policy = palloc0(sizeof(RowSecurityPolicy));
- policy->policy_name = policy_name_value;
+ policy->policy_name = pstrdup(policy_name_value);
policy->policy_id = policy_id;
- policy->cmd = cmd_value;
- policy->roles = roles;
+ policy->polcmd = cmd_value;
+ policy->roles = DatumGetArrayTypePCopy(roles_datum);
policy->qual = copyObject(qual_expr);
policy->with_check_qual = copyObject(with_check_qual);
- policy->hassublinks = contain_subplans((Node *) qual_expr) ||
- contain_subplans((Node *) with_check_qual);
+ policy->hassublinks = checkExprHasSubLink((Node *) qual_expr) ||
+ checkExprHasSubLink((Node *) with_check_qual);
rsdesc->policies = lcons(policy, rsdesc->policies);
MemoryContextSwitchTo(oldcxt);
+ /* clean up some (not all) of the junk ... */
if (qual_expr != NULL)
pfree(qual_expr);
-
if (with_check_qual != NULL)
pfree(with_check_qual);
}
+ systable_endscan(sscan);
+ heap_close(catalog, AccessShareLock);
+
/*
* Check if no policies were added
*
*/
if (rsdesc->policies == NIL)
{
- RowSecurityPolicy *policy = NULL;
+ RowSecurityPolicy *policy;
Datum role;
- oldcxt = MemoryContextSwitchTo(rscxt);
+ MemoryContextSwitchTo(rscxt);
role = ObjectIdGetDatum(ACL_ID_PUBLIC);
policy = palloc0(sizeof(RowSecurityPolicy));
policy->policy_name = pstrdup("default-deny policy");
policy->policy_id = InvalidOid;
- policy->cmd = '\0';
+ policy->polcmd = '*';
policy->roles = construct_array(&role, 1, OIDOID, sizeof(Oid), true,
'i');
policy->qual = (Expr *) makeConst(BOOLOID, -1, InvalidOid,
}
PG_CATCH();
{
- if (rscxt != NULL)
- MemoryContextDelete(rscxt);
+ /* Delete rscxt, first making sure it isn't active */
+ MemoryContextSwitchTo(oldcxt);
+ MemoryContextDelete(rscxt);
PG_RE_THROW();
}
PG_END_TRY();
- systable_endscan(sscan);
- heap_close(catalog, AccessShareLock);
-
+ /* Success --- attach the policy descriptor to the relcache entry */
relation->rd_rsdesc = rsdesc;
}
stmt->policy_name, RelationGetRelationName(target_table))));
values[Anum_pg_policy_polrelid - 1] = ObjectIdGetDatum(table_id);
- values[Anum_pg_policy_polname - 1]
- = DirectFunctionCall1(namein, CStringGetDatum(stmt->policy_name));
-
- if (polcmd)
- values[Anum_pg_policy_polcmd - 1] = CharGetDatum(polcmd);
- else
- isnull[Anum_pg_policy_polcmd - 1] = true;
-
+ values[Anum_pg_policy_polname - 1] = DirectFunctionCall1(namein,
+ CStringGetDatum(stmt->policy_name));
+ values[Anum_pg_policy_polcmd - 1] = CharGetDatum(polcmd);
values[Anum_pg_policy_polroles - 1] = PointerGetDatum(role_ids);
/* Add qual if present. */
if (qual)
- values[Anum_pg_policy_polqual - 1]
- = CStringGetTextDatum(nodeToString(qual));
+ values[Anum_pg_policy_polqual - 1] = CStringGetTextDatum(nodeToString(qual));
else
isnull[Anum_pg_policy_polqual - 1] = true;
/* Add WITH CHECK qual if present */
if (with_check_qual)
- values[Anum_pg_policy_polwithcheck - 1]
- = CStringGetTextDatum(nodeToString(with_check_qual));
+ values[Anum_pg_policy_polwithcheck - 1] = CStringGetTextDatum(nodeToString(with_check_qual));
else
isnull[Anum_pg_policy_polwithcheck - 1] = true;
cmd_datum = heap_getattr(policy_tuple, Anum_pg_policy_polcmd,
RelationGetDescr(pg_policy_rel),
&polcmd_isnull);
- if (polcmd_isnull)
- polcmd = 0;
- else
- polcmd = DatumGetChar(cmd_datum);
+ Assert(!polcmd_isnull);
+ polcmd = DatumGetChar(cmd_datum);
/*
* If the command is SELECT or DELETE then WITH CHECK should be NULL.
* query, then set hasSubLinks on the Query to force subLinks to be
* properly expanded.
*/
- if (hassublinks)
- root->hasSubLinks = hassublinks;
+ root->hasSubLinks |= hassublinks;
/* If we got this far, we must have added quals */
return true;
policy = (RowSecurityPolicy *) lfirst(item);
/* Always add ALL policies, if they exist. */
- if (policy->cmd == '\0' &&
+ if (policy->polcmd == '*' &&
check_role_for_policy(policy->roles, user_id))
policies = lcons(policy, policies);
- /* Build the list of policies to return. */
+ /* Add relevant command-specific policies to the list. */
switch(cmd)
{
case CMD_SELECT:
- if (policy->cmd == ACL_SELECT_CHR
+ if (policy->polcmd == ACL_SELECT_CHR
&& check_role_for_policy(policy->roles, user_id))
policies = lcons(policy, policies);
break;
case CMD_INSERT:
/* If INSERT then only need to add the WITH CHECK qual */
- if (policy->cmd == ACL_INSERT_CHR
+ if (policy->polcmd == ACL_INSERT_CHR
&& check_role_for_policy(policy->roles, user_id))
policies = lcons(policy, policies);
break;
case CMD_UPDATE:
- if (policy->cmd == ACL_UPDATE_CHR
+ if (policy->polcmd == ACL_UPDATE_CHR
&& check_role_for_policy(policy->roles, user_id))
policies = lcons(policy, policies);
break;
case CMD_DELETE:
- if (policy->cmd == ACL_DELETE_CHR
+ if (policy->polcmd == ACL_DELETE_CHR
&& check_role_for_policy(policy->roles, user_id))
policies = lcons(policy, policies);
break;
default:
- elog(ERROR, "unrecognized command type.");
+ elog(ERROR, "unrecognized policy command type %d", (int) cmd);
break;
}
}
policy = palloc0(sizeof(RowSecurityPolicy));
policy->policy_name = pstrdup("default-deny policy");
policy->policy_id = InvalidOid;
- policy->cmd = '\0';
+ policy->polcmd = '*';
policy->roles = construct_array(&role, 1, OIDOID, sizeof(Oid), true,
'i');
policy->qual = (Expr *) makeConst(BOOLOID, -1, InvalidOid,
if (policy1->policy_id != policy2->policy_id)
return false;
- if (policy1->cmd != policy2->cmd)
+ if (policy1->polcmd != policy2->polcmd)
return false;
if (policy1->hassublinks != policy2->hassublinks)
return false;
appendPQExpBuffer(query,
"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 "
+ " pg_catalog.array_to_string(ARRAY(SELECT pg_catalog.quote_ident(rolname) from pg_catalog.pg_roles WHERE oid = ANY(pol.polroles)), ', ') END AS polroles, "
+ "pg_catalog.pg_get_expr(pol.polqual, pol.polrelid) AS polqual, "
+ "pg_catalog.pg_get_expr(pol.polwithcheck, pol.polrelid) AS polwithcheck "
"FROM pg_catalog.pg_policy pol "
"WHERE polrelid = '%u'",
tbinfo->dobj.catId.oid);
{
/*
* No explicit policies to handle (only the default-deny policy,
- * which is handled as part of the table definition. Clean up and
+ * which is handled as part of the table definition). Clean up and
* return.
*/
PQclear(res);
polinfo[j].dobj.namespace = tbinfo->dobj.namespace;
polinfo[j].poltable = tbinfo;
polinfo[j].polname = pg_strdup(PQgetvalue(res, j, i_polname));
-
polinfo[j].dobj.name = pg_strdup(polinfo[j].polname);
- if (PQgetisnull(res, j, i_polcmd))
- polinfo[j].polcmd = NULL;
- else
- polinfo[j].polcmd = pg_strdup(PQgetvalue(res, j, i_polcmd));
-
+ polinfo[j].polcmd = pg_strdup(PQgetvalue(res, j, i_polcmd));
polinfo[j].polroles = pg_strdup(PQgetvalue(res, j, i_polroles));
if (PQgetisnull(res, j, i_polqual))
return;
}
- if (!polinfo->polcmd)
+ if (strcmp(polinfo->polcmd, "*") == 0)
cmd = "ALL";
else if (strcmp(polinfo->polcmd, "r") == 0)
cmd = "SELECT";
cmd = "DELETE";
else
{
- write_msg(NULL, "unexpected command type: '%s'\n", polinfo->polcmd);
+ write_msg(NULL, "unexpected policy command type: \"%s\"\n",
+ polinfo->polcmd);
exit_nicely(1);
}
query = createPQExpBuffer();
delqry = createPQExpBuffer();
- appendPQExpBuffer(query, "CREATE POLICY %s ON %s FOR %s",
- polinfo->polname, fmtId(tbinfo->dobj.name), cmd);
+ appendPQExpBuffer(query, "CREATE POLICY %s", fmtId(polinfo->polname));
+ appendPQExpBuffer(query, " ON %s FOR %s", fmtId(tbinfo->dobj.name), cmd);
if (polinfo->polroles != NULL)
appendPQExpBuffer(query, " TO %s", polinfo->polroles);
appendPQExpBuffer(query, ";\n");
- appendPQExpBuffer(delqry, "DROP POLICY %s ON %s;\n",
- polinfo->polname, fmtId(tbinfo->dobj.name));
+ appendPQExpBuffer(delqry, "DROP POLICY %s", fmtId(polinfo->polname));
+ appendPQExpBuffer(delqry, " ON %s;\n", fmtId(tbinfo->dobj.name));
ArchiveEntry(fout, polinfo->dobj.catId, polinfo->dobj.dumpId,
polinfo->dobj.name,
appendPQExpBuffer(&buf,
",\n pg_catalog.array_to_string(ARRAY(\n"
" SELECT polname\n"
- " || CASE WHEN polcmd IS NOT NULL THEN\n"
- " E' (' || polcmd || E')'\n"
+ " || CASE WHEN polcmd != '*' THEN\n"
+ " E' (' || polcmd || E'):'\n"
" ELSE E':' \n"
" END\n"
" || CASE WHEN polqual IS NOT NULL THEN\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 'w' THEN 'UPDATE'\n"
"WHEN 'd' THEN 'DELETE'\n"
+ "WHEN '*' THEN 'ALL'\n"
"END AS cmd\n"
"FROM pg_catalog.pg_policy pol\n"
"WHERE pol.polrelid = '%s' ORDER BY 1;",
*/
/* yyyymmddN */
-#define CATALOG_VERSION_NO 201412301
+#define CATALOG_VERSION_NO 201501241
#endif
{
NameData polname; /* Policy name. */
Oid polrelid; /* Oid of the relation with policy. */
- char polcmd; /* One of ACL_*_CHR, or \0 for all */
+ char polcmd; /* One of ACL_*_CHR, or '*' for all */
#ifdef CATALOG_VARLEN
- Oid polroles[1] /* Roles associated with policy, not-NULL */
+ Oid polroles[1]; /* Roles associated with policy, not-NULL */
pg_node_tree polqual; /* Policy quals. */
pg_node_tree polwithcheck; /* WITH CHECK quals. */
#endif
{
Oid policy_id; /* OID of the policy */
char *policy_name; /* Name of the policy */
- char cmd; /* Type of command policy is for */
+ char polcmd; /* Type of command policy is for */
ArrayType *roles; /* Array of roles policy is for */
Expr *qual; /* Expression to filter rows */
Expr *with_check_qual; /* Expression to limit rows allowed */
- bool hassublinks; /* If expression has sublinks */
+ bool hassublinks; /* If either expression has sublinks */
} RowSecurityPolicy;
typedef struct RowSecurityDesc
WHERE (pg_authid.oid = ANY (pol.polroles))
ORDER BY pg_authid.rolname)
END AS roles,
- CASE
- WHEN (pol.polcmd IS NULL) THEN 'ALL'::text
- ELSE
- CASE pol.polcmd
- WHEN 'r'::"char" THEN 'SELECT'::text
- WHEN 'a'::"char" THEN 'INSERT'::text
- WHEN 'u'::"char" THEN 'UPDATE'::text
- WHEN 'd'::"char" THEN 'DELETE'::text
- ELSE NULL::text
- END
+ CASE pol.polcmd
+ WHEN 'r'::"char" THEN 'SELECT'::text
+ WHEN 'a'::"char" THEN 'INSERT'::text
+ WHEN 'w'::"char" THEN 'UPDATE'::text
+ WHEN 'd'::"char" THEN 'DELETE'::text
+ WHEN '*'::"char" THEN 'ALL'::text
+ ELSE NULL::text
END AS cmd,
pg_get_expr(pol.polqual, pol.polrelid) AS qual,
pg_get_expr(pol.polwithcheck, pol.polrelid) AS with_check