On 07/03/2015 10:03 AM, Noah Misch wrote:
> (4) When DefineQueryRewrite() is about to convert a table to a view, it checks
> the table for features unavailable to views.  For example, it rejects tables
> having triggers.  It omits to reject tables having relrowsecurity or a
> pg_policy record.  Test case:

Please see the attached patch for this issue. Comments?

Thanks,

Joe

diff --git a/src/backend/commands/policy.c b/src/backend/commands/policy.c
index 17b48d4..aa858fa 100644
*** a/src/backend/commands/policy.c
--- b/src/backend/commands/policy.c
*************** get_relation_policy_oid(Oid relid, const
*** 1002,1004 ****
--- 1002,1033 ----
  
  	return policy_oid;
  }
+ 
+ /*
+  * relation_has_policies - Determine if relation has any policies
+  */
+ bool
+ relation_has_policies(Relation rel)
+ {
+ 	Relation	catalog;
+ 	ScanKeyData skey;
+ 	SysScanDesc sscan;
+ 	HeapTuple	policy_tuple;
+ 	bool		ret = false;
+ 
+ 	catalog = heap_open(PolicyRelationId, AccessShareLock);
+ 	ScanKeyInit(&skey,
+ 				Anum_pg_policy_polrelid,
+ 				BTEqualStrategyNumber, F_OIDEQ,
+ 				ObjectIdGetDatum(RelationGetRelid(rel)));
+ 	sscan = systable_beginscan(catalog, PolicyPolrelidPolnameIndexId, true,
+ 							   NULL, 1, &skey);
+ 	policy_tuple = systable_getnext(sscan);
+ 	if (HeapTupleIsValid(policy_tuple))
+ 		ret = true;
+ 
+ 	systable_endscan(sscan);
+ 	heap_close(catalog, AccessShareLock);
+ 
+ 	return ret;
+ }
diff --git a/src/backend/rewrite/rewriteDefine.c b/src/backend/rewrite/rewriteDefine.c
index a88d73e..39c83a6 100644
*** a/src/backend/rewrite/rewriteDefine.c
--- b/src/backend/rewrite/rewriteDefine.c
***************
*** 27,32 ****
--- 27,33 ----
  #include "catalog/objectaccess.h"
  #include "catalog/pg_rewrite.h"
  #include "catalog/storage.h"
+ #include "commands/policy.h"
  #include "miscadmin.h"
  #include "nodes/nodeFuncs.h"
  #include "parser/parse_utilcmd.h"
*************** DefineQueryRewrite(char *rulename,
*** 410,420 ****
  		 *
  		 * If so, check that the relation is empty because the storage for the
  		 * relation is going to be deleted.  Also insist that the rel not have
! 		 * any triggers, indexes, or child tables.  (Note: these tests are too
! 		 * strict, because they will reject relations that once had such but
! 		 * don't anymore.  But we don't really care, because this whole
! 		 * business of converting relations to views is just a kluge to allow
! 		 * dump/reload of views that participate in circular dependencies.)
  		 */
  		if (event_relation->rd_rel->relkind != RELKIND_VIEW &&
  			event_relation->rd_rel->relkind != RELKIND_MATVIEW)
--- 411,422 ----
  		 *
  		 * If so, check that the relation is empty because the storage for the
  		 * relation is going to be deleted.  Also insist that the rel not have
! 		 * any triggers, indexes, child tables, policies, or RLS enabled.
! 		 * (Note: these tests are too strict, because they will reject
! 		 * relations that once had such but don't anymore.  But we don't
! 		 * really care, because this whole business of converting relations
! 		 * to views is just a kluge to allow dump/reload of views that
! 		 * participate in circular dependencies.)
  		 */
  		if (event_relation->rd_rel->relkind != RELKIND_VIEW &&
  			event_relation->rd_rel->relkind != RELKIND_MATVIEW)
*************** DefineQueryRewrite(char *rulename,
*** 451,456 ****
--- 453,470 ----
  						 errmsg("could not convert table \"%s\" to a view because it has child tables",
  								RelationGetRelationName(event_relation))));
  
+ 			if (event_relation->rd_rel->relrowsecurity)
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ 						 errmsg("could not convert table \"%s\" to a view because it has row security enabled",
+ 								RelationGetRelationName(event_relation))));
+ 
+ 			if (relation_has_policies(event_relation))
+ 				ereport(ERROR,
+ 						(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
+ 						 errmsg("could not convert table \"%s\" to a view because it has row security policies",
+ 								RelationGetRelationName(event_relation))));
+ 
  			RelisBecomingView = true;
  		}
  	}
diff --git a/src/include/commands/policy.h b/src/include/commands/policy.h
index ac322e0..be00043 100644
*** a/src/include/commands/policy.h
--- b/src/include/commands/policy.h
*************** extern Oid get_relation_policy_oid(Oid r
*** 31,35 ****
--- 31,36 ----
  
  extern ObjectAddress rename_policy(RenameStmt *stmt);
  
+ extern bool relation_has_policies(Relation rel);
  
  #endif   /* POLICY_H */
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index 72361e8..2a8db6d 100644
*** a/src/test/regress/expected/rowsecurity.out
--- b/src/test/regress/expected/rowsecurity.out
*************** SELECT * FROM coll_t;
*** 2908,2913 ****
--- 2908,2936 ----
  
  ROLLBACK;
  --
+ -- Converting table to view
+ --
+ BEGIN;
+ SET ROW_SECURITY = FORCE;
+ CREATE TABLE t (c int);
+ CREATE POLICY p ON t USING (c % 2 = 1);
+ ALTER TABLE t ENABLE ROW LEVEL SECURITY;
+ SAVEPOINT q;
+ CREATE RULE "_RETURN" AS ON SELECT TO t DO INSTEAD
+   SELECT * FROM generate_series(1,5) t0(c); -- fails due to row level security enabled
+ ERROR:  could not convert table "t" to a view because it has row security enabled
+ ROLLBACK TO q;
+ ALTER TABLE t DISABLE ROW LEVEL SECURITY;
+ SAVEPOINT q;
+ CREATE RULE "_RETURN" AS ON SELECT TO t DO INSTEAD
+   SELECT * FROM generate_series(1,5) t0(c); -- fails due to policy p on t
+ ERROR:  could not convert table "t" to a view because it has row security policies
+ ROLLBACK TO q;
+ DROP POLICY p ON t;
+ CREATE RULE "_RETURN" AS ON SELECT TO t DO INSTEAD
+   SELECT * FROM generate_series(1,5) t0(c); -- succeeds
+ ROLLBACK;
+ --
  -- Clean up objects
  --
  RESET SESSION AUTHORIZATION;
diff --git a/src/test/regress/sql/rowsecurity.sql b/src/test/regress/sql/rowsecurity.sql
index f588fa2..ad17ae3 100644
*** a/src/test/regress/sql/rowsecurity.sql
--- b/src/test/regress/sql/rowsecurity.sql
*************** SELECT * FROM coll_t;
*** 1202,1207 ****
--- 1202,1232 ----
  ROLLBACK;
  
  --
+ -- Converting table to view
+ --
+ BEGIN;
+ SET ROW_SECURITY = FORCE;
+ CREATE TABLE t (c int);
+ CREATE POLICY p ON t USING (c % 2 = 1);
+ ALTER TABLE t ENABLE ROW LEVEL SECURITY;
+ 
+ SAVEPOINT q;
+ CREATE RULE "_RETURN" AS ON SELECT TO t DO INSTEAD
+   SELECT * FROM generate_series(1,5) t0(c); -- fails due to row level security enabled
+ ROLLBACK TO q;
+ 
+ ALTER TABLE t DISABLE ROW LEVEL SECURITY;
+ SAVEPOINT q;
+ CREATE RULE "_RETURN" AS ON SELECT TO t DO INSTEAD
+   SELECT * FROM generate_series(1,5) t0(c); -- fails due to policy p on t
+ ROLLBACK TO q;
+ 
+ DROP POLICY p ON t;
+ CREATE RULE "_RETURN" AS ON SELECT TO t DO INSTEAD
+   SELECT * FROM generate_series(1,5) t0(c); -- succeeds
+ ROLLBACK;
+ 
+ --
  -- Clean up objects
  --
  RESET SESSION AUTHORIZATION;
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to