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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers