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