From: Stephen Frost <sfrost@snowman.net>
Date: Fri, 3 Oct 2014 20:31:53 +0000 (-0400)
Subject: Fix CreatePolicy, pg_dump -v; psql and doc updates
X-Git-Tag: REL9_5_ALPHA1~1395
X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=78d72563ef141ddc507ddd5ae77db613a309041a;p=postgresql

Fix CreatePolicy, pg_dump -v; psql and doc updates

Peter G pointed out that valgrind was, rightfully, complaining about
CreatePolicy() ending up copying beyond the end of the parsed policy
name.  Name is a fixed-size type and we need to use namein (through
DirectFunctionCall1()) to flush out the entire array before we pass
it down to heap_form_tuple.

Michael Paquier pointed out that pg_dump --verbose was missing a
newline and Fabrízio de Royes Mello further pointed out that the
schema was also missing from the messages, so fix those also.

Also, based on an off-list comment from Kevin, rework the psql \d
output to facilitate copy/pasting into a new CREATE or ALTER POLICY
command.

Lastly, improve the pg_policies view and update the documentation for
it, along with a few other minor doc corrections based on an off-list
discussion with Adam Brightwell.
---

diff --git a/doc/src/sgml/catalogs.sgml b/doc/src/sgml/catalogs.sgml
index a6ca290cb3..f4617b67e9 100644
--- a/doc/src/sgml/catalogs.sgml
+++ b/doc/src/sgml/catalogs.sgml
@@ -5396,6 +5396,13 @@
       <entry>The command type to which the row-security policy is applied.</entry>
      </row>
 
+     <row>
+      <entry><structfield>rsecroles</structfield></entry>
+      <entry><type>char</type></entry>
+      <entry></entry>
+      <entry>The roles to which the row-security policy is applied.</entry>
+     </row>
+
      <row>
       <entry><structfield>rsecqual</structfield></entry>
       <entry><type>pg_node_tree</type></entry>
@@ -5417,8 +5424,8 @@
   <note>
    <para>
     <literal>pg_class.relrowsecurity</literal>
-    True if the table has row-security enabled.
-    Must be true if the table has a row-security policy in this catalog.
+    True if the table has row-security enabled.  Policies will not be applied
+    unless row-security is enabled on the table.
    </para>
   </note>
 
@@ -7299,6 +7306,11 @@
       <entry>materialized views</entry>
      </row>
 
+     <row>
+      <entry><link linkend="view-pg-policies"><structname>pg_policies</structname></link></entry>
+      <entry>policies</entry>
+     </row>
+
      <row>
       <entry><link linkend="view-pg-prepared-statements"><structname>pg_prepared_statements</structname></link></entry>
       <entry>prepared statements</entry>
@@ -8146,6 +8158,81 @@ SELECT * FROM pg_locks pl LEFT JOIN pg_prepared_xacts ppx
 
  </sect1>
 
+ <sect1 id="view-pg-policies">
+  <title><structname>pg_policies</structname></title>
+
+  <indexterm zone="view-pg-policies">
+   <primary>pg_policies</primary>
+  </indexterm>
+
+  <para>
+   The view <structname>pg_policies</structname> provides access to
+   useful information about each policy in the database.
+  </para>
+
+  <table>
+   <title><structname>pg_policies</> 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>schemaname</structfield></entry>
+      <entry><type>name</type></entry>
+      <entry><literal><link linkend="catalog-pg-namespace"><structname>pg_namespace</structname></link>.nspname</literal></entry>
+      <entry>Name of schema containing table policy is on</entry>
+     </row>
+     <row>
+      <entry><structfield>tablename</structfield></entry>
+      <entry><type>name</type></entry>
+      <entry><literal><link linkend="catalog-pg-class"><structname>pg_class</structname></link>.relname</literal></entry>
+      <entry>Name of table policy is on</entry>
+     </row>
+     <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>Name of policy</entry>
+     </row>
+     <row>
+      <entry><structfield>cmd</structfield></entry>
+      <entry><type>text</type></entry>
+      <entry></entry>
+      <entry>The command type to which the policy is applied.</entry>
+     </row>
+     <row>
+      <entry><structfield>roles</structfield></entry>
+      <entry><type>name[]</type></entry>
+      <entry></entry>
+      <entry>The roles to which this policy applies.</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>
+     </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>
+     </row>
+    </tbody>
+   </tgroup>
+  </table>
+
+ </sect1>
+
  <sect1 id="view-pg-prepared-statements">
   <title><structname>pg_prepared_statements</structname></title>
 
diff --git a/src/backend/catalog/system_views.sql b/src/backend/catalog/system_views.sql
index da99fd63e8..a819952c75 100644
--- a/src/backend/catalog/system_views.sql
+++ b/src/backend/catalog/system_views.sql
@@ -65,8 +65,9 @@ CREATE VIEW pg_user AS
 
 CREATE VIEW pg_policies AS
     SELECT
+        N.nspname AS schemaname,
+        C.relname AS tablename,
         rs.rsecpolname AS policyname,
-        (SELECT relname FROM pg_catalog.pg_class WHERE oid = rs.rsecrelid) AS tablename,
         CASE
             WHEN rs.rsecroles = '{0}' THEN
                 string_to_array('public', '')
@@ -78,8 +79,8 @@ CREATE VIEW pg_policies AS
                     WHERE oid = ANY (rs.rsecroles) ORDER BY 1
                 )
         END AS roles,
-		CASE WHEN rs.rseccmd IS NULL THEN 'ALL' ELSE
-			CASE rs.rseccmd
+        CASE WHEN rs.rseccmd IS NULL THEN 'ALL' ELSE
+            CASE rs.rseccmd
                 WHEN 'r' THEN 'SELECT'
                 WHEN 'a' THEN 'INSERT'
                 WHEN 'u' THEN 'UPDATE'
@@ -89,7 +90,8 @@ CREATE VIEW pg_policies AS
         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
-    ORDER BY 1;
+    JOIN pg_catalog.pg_class C ON (C.oid = rs.rsecrelid)
+    LEFT JOIN pg_catalog.pg_namespace N ON (N.oid = C.relnamespace);
 
 CREATE VIEW pg_rules AS
     SELECT
diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 33bf031346..8e6393c8c0 100644
--- a/src/backend/commands/policy.c
+++ b/src/backend/commands/policy.c
@@ -556,7 +556,7 @@ CreatePolicy(CreatePolicyStmt *stmt)
 
 	values[Anum_pg_rowsecurity_rsecrelid - 1] = ObjectIdGetDatum(table_id);
 	values[Anum_pg_rowsecurity_rsecpolname - 1]
-		= CStringGetDatum(stmt->policy_name);
+		= DirectFunctionCall1(namein, CStringGetDatum(stmt->policy_name));
 
 	if (rseccmd)
 		values[Anum_pg_rowsecurity_rseccmd - 1] = CharGetDatum(rseccmd);
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index 12811a801a..1a9e82e920 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -2803,7 +2803,8 @@ getRowSecurity(Archive *fout, TableInfo tblinfo[], int numTables)
 			continue;
 
 		if (g_verbose)
-			write_msg(NULL, "reading row-security enabled for table \"%s\"",
+			write_msg(NULL, "reading row-security enabled for table \"%s\".\"%s\"\n",
+					  tbinfo->dobj.namespace->dobj.name,
 					  tbinfo->dobj.name);
 
 		/*
@@ -2833,7 +2834,8 @@ getRowSecurity(Archive *fout, TableInfo tblinfo[], int numTables)
 		}
 
 		if (g_verbose)
-			write_msg(NULL, "reading row-security policies for table \"%s\"\n",
+			write_msg(NULL, "reading row-security policies for table \"%s\".\"%s\"\n",
+					  tbinfo->dobj.namespace->dobj.name,
 					  tbinfo->dobj.name);
 
 		/*
diff --git a/src/bin/psql/describe.c b/src/bin/psql/describe.c
index 074be57696..267f365170 100644
--- a/src/bin/psql/describe.c
+++ b/src/bin/psql/describe.c
@@ -2011,10 +2011,15 @@ describeOneTableDetails(const char *schemaname,
 
 			printfPQExpBuffer(&buf,
 						   "SELECT rs.rsecpolname,\n"
-						   "CASE WHEN rs.rsecroles = '{0}' THEN NULL ELSE array(select rolname from pg_roles where oid = any (rs.rsecroles) order by 1) END,\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"
-						   "rs.rseccmd AS cmd\n"
+						   "CASE rs.rseccmd \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;",
 							  oid);
@@ -2046,26 +2051,25 @@ describeOneTableDetails(const char *schemaname,
 									  PQgetvalue(result, i, 0));
 
 				if (!PQgetisnull(result, i, 4))
-					appendPQExpBuffer(&buf, " (%s)",
+					appendPQExpBuffer(&buf, " FOR %s",
 									  PQgetvalue(result, i, 4));
 
+				if (!PQgetisnull(result, i, 1))
+				{
+					appendPQExpBuffer(&buf, "\n      TO %s",
+									  PQgetvalue(result, i, 1));
+				}
+
 				if (!PQgetisnull(result, i, 2))
-					appendPQExpBuffer(&buf, " EXPRESSION %s",
+					appendPQExpBuffer(&buf, "\n      USING %s",
 									  PQgetvalue(result, i, 2));
 
 				if (!PQgetisnull(result, i, 3))
-					appendPQExpBuffer(&buf, " WITH CHECK %s",
+					appendPQExpBuffer(&buf, "\n      WITH CHECK %s",
 									  PQgetvalue(result, i, 3));
 
 				printTableAddFooter(&cont, buf.data);
 
-				if (!PQgetisnull(result, i, 1))
-				{
-					printfPQExpBuffer(&buf, "          APPLIED TO %s",
-									  PQgetvalue(result, i, 1));
-
-					printTableAddFooter(&cont, buf.data);
-				}
 			}
 			PQclear(result);
 		}
diff --git a/src/test/regress/expected/rules.out b/src/test/regress/expected/rules.out
index c53e7851cc..c79b45c53a 100644
--- a/src/test/regress/expected/rules.out
+++ b/src/test/regress/expected/rules.out
@@ -1353,10 +1353,9 @@ pg_matviews| SELECT n.nspname AS schemaname,
      LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace)))
      LEFT JOIN pg_tablespace t ON ((t.oid = c.reltablespace)))
   WHERE (c.relkind = 'm'::"char");
-pg_policies| SELECT rs.rsecpolname AS policyname,
-    ( SELECT pg_class.relname
-           FROM pg_class
-          WHERE (pg_class.oid = rs.rsecrelid)) AS tablename,
+pg_policies| SELECT n.nspname AS schemaname,
+    c.relname AS tablename,
+    rs.rsecpolname AS policyname,
         CASE
             WHEN (rs.rsecroles = '{0}'::oid[]) THEN (string_to_array('public'::text, ''::text))::name[]
             ELSE ARRAY( SELECT pg_authid.rolname
@@ -1377,8 +1376,9 @@ pg_policies| SELECT rs.rsecpolname AS policyname,
         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
-  ORDER BY rs.rsecpolname;
+   FROM ((pg_rowsecurity rs
+     JOIN pg_class c ON ((c.oid = rs.rsecrelid)))
+     LEFT JOIN pg_namespace n ON ((n.oid = c.relnamespace)));
 pg_prepared_statements| SELECT p.name,
     p.statement,
     p.prepare_time,