On 06/09/2017 06:16 AM, Joe Conway wrote:
> On 06/08/2017 11:09 PM, Noah Misch wrote:
>> On Wed, Jun 07, 2017 at 08:45:20AM -0700, Joe Conway wrote:
>>> On 06/07/2017 06:49 AM, Mike Palmiotto wrote:
>>> > I ended up narrowing it down to 4 tables (one parent and 3 partitions)
>>> > in order to demonstrate policy sorting and order of RLS/partition
>>> > constraint checking. It should be much more straight-forward now, but
>>> > let me know if there are any further recommended changes.
>>> 
>>> Thanks, will take a look towards the end of the day.
>> 
>> This PostgreSQL 10 open item is past due for your status update.  Kindly send
>> a status update within 24 hours, and include a date for your subsequent 
>> status
>> update.  Refer to the policy on open item ownership:
>> https://www.postgresql.org/message-id/20170404140717.GA2675809%40tornado.leadboat.com
> 
> I started reviewing the latest patch last night and will try to finish
> up this afternoon (west coast USA time).

I left the actual (2 line) code change untouched, but I tweaked the
regression test changes a bit. If there are no complaints I will push
tomorrow (Saturday).

Joe

-- 
Crunchy Data - http://crunchydata.com
PostgreSQL Support for Secure Enterprises
Consulting, Training, & Open Source Development
diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c
index 35ff8bb..6cd73c1 100644
*** a/src/backend/rewrite/rewriteHandler.c
--- b/src/backend/rewrite/rewriteHandler.c
*************** fireRIRrules(Query *parsetree, List *act
*** 1835,1841 ****
  
  		/* Only normal relations can have RLS policies */
  		if (rte->rtekind != RTE_RELATION ||
! 			rte->relkind != RELKIND_RELATION)
  			continue;
  
  		rel = heap_open(rte->relid, NoLock);
--- 1835,1842 ----
  
  		/* Only normal relations can have RLS policies */
  		if (rte->rtekind != RTE_RELATION ||
! 			(rte->relkind != RELKIND_RELATION &&
! 			rte->relkind != RELKIND_PARTITIONED_TABLE))
  			continue;
  
  		rel = heap_open(rte->relid, NoLock);
diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out
index 7bf2936..d382a9f 100644
*** a/src/test/regress/expected/rowsecurity.out
--- b/src/test/regress/expected/rowsecurity.out
*************** EXPLAIN (COSTS OFF) SELECT * FROM t1 WHE
*** 899,904 ****
--- 899,1332 ----
           Filter: f_leak(b)
  (7 rows)
  
+ --
+ -- Partitioned Tables
+ --
+ SET SESSION AUTHORIZATION regress_rls_alice;
+ CREATE TABLE part_document (
+     did         int,
+     cid         int,
+     dlevel      int not null,
+     dauthor     name,
+     dtitle      text
+ ) PARTITION BY RANGE (cid);
+ GRANT ALL ON part_document TO public;
+ -- Create partitions for document categories
+ CREATE TABLE part_document_fiction PARTITION OF part_document FOR VALUES FROM (11) to (12);
+ CREATE TABLE part_document_satire PARTITION OF part_document FOR VALUES FROM (55) to (56);
+ CREATE TABLE part_document_nonfiction PARTITION OF part_document FOR VALUES FROM (99) to (100);
+ GRANT ALL ON part_document_fiction TO public;
+ GRANT ALL ON part_document_satire TO public;
+ GRANT ALL ON part_document_nonfiction TO public;
+ INSERT INTO part_document VALUES
+     ( 1, 11, 1, 'regress_rls_bob', 'my first novel'),
+     ( 2, 11, 2, 'regress_rls_bob', 'my second novel'),
+     ( 3, 99, 2, 'regress_rls_bob', 'my science textbook'),
+     ( 4, 55, 1, 'regress_rls_bob', 'my first satire'),
+     ( 5, 99, 2, 'regress_rls_bob', 'my history book'),
+     ( 6, 11, 1, 'regress_rls_carol', 'great science fiction'),
+     ( 7, 99, 2, 'regress_rls_carol', 'great technology book'),
+     ( 8, 55, 2, 'regress_rls_carol', 'great satire'),
+     ( 9, 11, 1, 'regress_rls_dave', 'awesome science fiction'),
+     (10, 99, 2, 'regress_rls_dave', 'awesome technology book');
+ ALTER TABLE part_document ENABLE ROW LEVEL SECURITY;
+ -- Create policy on parent
+ -- user's security level must be higher than or equal to document's
+ CREATE POLICY pp1 ON part_document AS PERMISSIVE
+     USING (dlevel <= (SELECT seclv FROM uaccount WHERE pguser = current_user));
+ -- Dave is only allowed to see cid < 55
+ CREATE POLICY pp1r ON part_document AS RESTRICTIVE TO regress_rls_dave
+     USING (cid < 55);
+ \d+ part_document
+                           Table "regress_rls_schema.part_document"
+  Column  |  Type   | Collation | Nullable | Default | Storage  | Stats target | Description 
+ ---------+---------+-----------+----------+---------+----------+--------------+-------------
+  did     | integer |           |          |         | plain    |              | 
+  cid     | integer |           |          |         | plain    |              | 
+  dlevel  | integer |           | not null |         | plain    |              | 
+  dauthor | name    |           |          |         | plain    |              | 
+  dtitle  | text    |           |          |         | extended |              | 
+ Partition key: RANGE (cid)
+ Policies:
+     POLICY "pp1"
+       USING ((dlevel <= ( SELECT uaccount.seclv
+    FROM uaccount
+   WHERE (uaccount.pguser = CURRENT_USER))))
+     POLICY "pp1r" AS RESTRICTIVE
+       TO regress_rls_dave
+       USING ((cid < 55))
+ Partitions: part_document_fiction FOR VALUES FROM (11) TO (12),
+             part_document_nonfiction FOR VALUES FROM (99) TO (100),
+             part_document_satire FOR VALUES FROM (55) TO (56)
+ 
+ SELECT * FROM pg_policies WHERE schemaname = 'regress_rls_schema' AND tablename like '%part_document%' ORDER BY policyname;
+      schemaname     |   tablename   | policyname | permissive  |       roles        | cmd |                    qual                    | with_check 
+ --------------------+---------------+------------+-------------+--------------------+-----+--------------------------------------------+------------
+  regress_rls_schema | part_document | pp1        | PERMISSIVE  | {public}           | ALL | (dlevel <= ( SELECT uaccount.seclv        +| 
+                     |               |            |             |                    |     |    FROM uaccount                          +| 
+                     |               |            |             |                    |     |   WHERE (uaccount.pguser = CURRENT_USER))) | 
+  regress_rls_schema | part_document | pp1r       | RESTRICTIVE | {regress_rls_dave} | ALL | (cid < 55)                                 | 
+ (2 rows)
+ 
+ -- viewpoint from regress_rls_bob
+ SET SESSION AUTHORIZATION regress_rls_bob;
+ SET row_security TO ON;
+ SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did;
+ NOTICE:  f_leak => my first novel
+ NOTICE:  f_leak => great science fiction
+ NOTICE:  f_leak => awesome science fiction
+ NOTICE:  f_leak => my first satire
+  did | cid | dlevel |      dauthor      |         dtitle          
+ -----+-----+--------+-------------------+-------------------------
+    1 |  11 |      1 | regress_rls_bob   | my first novel
+    4 |  55 |      1 | regress_rls_bob   | my first satire
+    6 |  11 |      1 | regress_rls_carol | great science fiction
+    9 |  11 |      1 | regress_rls_dave  | awesome science fiction
+ (4 rows)
+ 
+ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle);
+                      QUERY PLAN                      
+ -----------------------------------------------------
+  Append
+    InitPlan 1 (returns $0)
+      ->  Index Scan using uaccount_pkey on uaccount
+            Index Cond: (pguser = CURRENT_USER)
+    ->  Seq Scan on part_document_fiction
+          Filter: ((dlevel <= $0) AND f_leak(dtitle))
+    ->  Seq Scan on part_document_satire
+          Filter: ((dlevel <= $0) AND f_leak(dtitle))
+    ->  Seq Scan on part_document_nonfiction
+          Filter: ((dlevel <= $0) AND f_leak(dtitle))
+ (10 rows)
+ 
+ -- viewpoint from regress_rls_carol
+ SET SESSION AUTHORIZATION regress_rls_carol;
+ SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did;
+ NOTICE:  f_leak => my first novel
+ NOTICE:  f_leak => my second novel
+ NOTICE:  f_leak => great science fiction
+ NOTICE:  f_leak => awesome science fiction
+ NOTICE:  f_leak => my first satire
+ NOTICE:  f_leak => great satire
+ NOTICE:  f_leak => my science textbook
+ NOTICE:  f_leak => my history book
+ NOTICE:  f_leak => great technology book
+ NOTICE:  f_leak => awesome technology book
+  did | cid | dlevel |      dauthor      |         dtitle          
+ -----+-----+--------+-------------------+-------------------------
+    1 |  11 |      1 | regress_rls_bob   | my first novel
+    2 |  11 |      2 | regress_rls_bob   | my second novel
+    3 |  99 |      2 | regress_rls_bob   | my science textbook
+    4 |  55 |      1 | regress_rls_bob   | my first satire
+    5 |  99 |      2 | regress_rls_bob   | my history book
+    6 |  11 |      1 | regress_rls_carol | great science fiction
+    7 |  99 |      2 | regress_rls_carol | great technology book
+    8 |  55 |      2 | regress_rls_carol | great satire
+    9 |  11 |      1 | regress_rls_dave  | awesome science fiction
+   10 |  99 |      2 | regress_rls_dave  | awesome technology book
+ (10 rows)
+ 
+ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle);
+                      QUERY PLAN                      
+ -----------------------------------------------------
+  Append
+    InitPlan 1 (returns $0)
+      ->  Index Scan using uaccount_pkey on uaccount
+            Index Cond: (pguser = CURRENT_USER)
+    ->  Seq Scan on part_document_fiction
+          Filter: ((dlevel <= $0) AND f_leak(dtitle))
+    ->  Seq Scan on part_document_satire
+          Filter: ((dlevel <= $0) AND f_leak(dtitle))
+    ->  Seq Scan on part_document_nonfiction
+          Filter: ((dlevel <= $0) AND f_leak(dtitle))
+ (10 rows)
+ 
+ -- viewpoint from regress_rls_dave
+ SET SESSION AUTHORIZATION regress_rls_dave;
+ SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did;
+ NOTICE:  f_leak => my first novel
+ NOTICE:  f_leak => my second novel
+ NOTICE:  f_leak => great science fiction
+ NOTICE:  f_leak => awesome science fiction
+  did | cid | dlevel |      dauthor      |         dtitle          
+ -----+-----+--------+-------------------+-------------------------
+    1 |  11 |      1 | regress_rls_bob   | my first novel
+    2 |  11 |      2 | regress_rls_bob   | my second novel
+    6 |  11 |      1 | regress_rls_carol | great science fiction
+    9 |  11 |      1 | regress_rls_dave  | awesome science fiction
+ (4 rows)
+ 
+ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle);
+                              QUERY PLAN                             
+ --------------------------------------------------------------------
+  Append
+    InitPlan 1 (returns $0)
+      ->  Index Scan using uaccount_pkey on uaccount
+            Index Cond: (pguser = CURRENT_USER)
+    ->  Seq Scan on part_document_fiction
+          Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
+ (6 rows)
+ 
+ -- pp1 ERROR
+ INSERT INTO part_document VALUES (100, 11, 5, 'regress_rls_dave', 'testing pp1'); -- fail
+ ERROR:  new row violates row-level security policy for table "part_document"
+ -- pp1r ERROR
+ INSERT INTO part_document VALUES (100, 99, 1, 'regress_rls_dave', 'testing pp1r'); -- fail
+ ERROR:  new row violates row-level security policy "pp1r" for table "part_document"
+ -- Show that RLS policy does not apply for direct inserts to children
+ -- This should fail with RLS POLICY pp1r violation.
+ INSERT INTO part_document VALUES (100, 55, 1, 'regress_rls_dave', 'testing RLS with partitions'); -- fail
+ ERROR:  new row violates row-level security policy "pp1r" for table "part_document"
+ -- But this should succeed.
+ INSERT INTO part_document_satire VALUES (100, 55, 1, 'regress_rls_dave', 'testing RLS with partitions'); -- success
+ -- We still cannot see the row using the parent
+ SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did;
+ NOTICE:  f_leak => my first novel
+ NOTICE:  f_leak => my second novel
+ NOTICE:  f_leak => great science fiction
+ NOTICE:  f_leak => awesome science fiction
+  did | cid | dlevel |      dauthor      |         dtitle          
+ -----+-----+--------+-------------------+-------------------------
+    1 |  11 |      1 | regress_rls_bob   | my first novel
+    2 |  11 |      2 | regress_rls_bob   | my second novel
+    6 |  11 |      1 | regress_rls_carol | great science fiction
+    9 |  11 |      1 | regress_rls_dave  | awesome science fiction
+ (4 rows)
+ 
+ -- But we can if we look directly
+ SELECT * FROM part_document_satire WHERE f_leak(dtitle) ORDER BY did;
+ NOTICE:  f_leak => my first satire
+ NOTICE:  f_leak => great satire
+ NOTICE:  f_leak => testing RLS with partitions
+  did | cid | dlevel |      dauthor      |           dtitle            
+ -----+-----+--------+-------------------+-----------------------------
+    4 |  55 |      1 | regress_rls_bob   | my first satire
+    8 |  55 |      2 | regress_rls_carol | great satire
+  100 |  55 |      1 | regress_rls_dave  | testing RLS with partitions
+ (3 rows)
+ 
+ -- Turn on RLS and create policy on child to show RLS is checked before constraints
+ SET SESSION AUTHORIZATION regress_rls_alice;
+ ALTER TABLE part_document_satire ENABLE ROW LEVEL SECURITY;
+ CREATE POLICY pp3 ON part_document_satire AS RESTRICTIVE
+     USING (cid < 55);
+ -- This should fail with RLS violation now.
+ SET SESSION AUTHORIZATION regress_rls_dave;
+ INSERT INTO part_document_satire VALUES (101, 55, 1, 'regress_rls_dave', 'testing RLS with partitions'); -- fail
+ ERROR:  new row violates row-level security policy for table "part_document_satire"
+ -- And now we cannot see directly into the partition either, due to RLS
+ SELECT * FROM part_document_satire WHERE f_leak(dtitle) ORDER BY did;
+  did | cid | dlevel | dauthor | dtitle 
+ -----+-----+--------+---------+--------
+ (0 rows)
+ 
+ -- The parent looks same as before
+ -- viewpoint from regress_rls_dave
+ SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did;
+ NOTICE:  f_leak => my first novel
+ NOTICE:  f_leak => my second novel
+ NOTICE:  f_leak => great science fiction
+ NOTICE:  f_leak => awesome science fiction
+  did | cid | dlevel |      dauthor      |         dtitle          
+ -----+-----+--------+-------------------+-------------------------
+    1 |  11 |      1 | regress_rls_bob   | my first novel
+    2 |  11 |      2 | regress_rls_bob   | my second novel
+    6 |  11 |      1 | regress_rls_carol | great science fiction
+    9 |  11 |      1 | regress_rls_dave  | awesome science fiction
+ (4 rows)
+ 
+ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle);
+                              QUERY PLAN                             
+ --------------------------------------------------------------------
+  Append
+    InitPlan 1 (returns $0)
+      ->  Index Scan using uaccount_pkey on uaccount
+            Index Cond: (pguser = CURRENT_USER)
+    ->  Seq Scan on part_document_fiction
+          Filter: ((cid < 55) AND (dlevel <= $0) AND f_leak(dtitle))
+ (6 rows)
+ 
+ -- viewpoint from regress_rls_carol
+ SET SESSION AUTHORIZATION regress_rls_carol;
+ SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did;
+ NOTICE:  f_leak => my first novel
+ NOTICE:  f_leak => my second novel
+ NOTICE:  f_leak => great science fiction
+ NOTICE:  f_leak => awesome science fiction
+ NOTICE:  f_leak => my first satire
+ NOTICE:  f_leak => great satire
+ NOTICE:  f_leak => testing RLS with partitions
+ NOTICE:  f_leak => my science textbook
+ NOTICE:  f_leak => my history book
+ NOTICE:  f_leak => great technology book
+ NOTICE:  f_leak => awesome technology book
+  did | cid | dlevel |      dauthor      |           dtitle            
+ -----+-----+--------+-------------------+-----------------------------
+    1 |  11 |      1 | regress_rls_bob   | my first novel
+    2 |  11 |      2 | regress_rls_bob   | my second novel
+    3 |  99 |      2 | regress_rls_bob   | my science textbook
+    4 |  55 |      1 | regress_rls_bob   | my first satire
+    5 |  99 |      2 | regress_rls_bob   | my history book
+    6 |  11 |      1 | regress_rls_carol | great science fiction
+    7 |  99 |      2 | regress_rls_carol | great technology book
+    8 |  55 |      2 | regress_rls_carol | great satire
+    9 |  11 |      1 | regress_rls_dave  | awesome science fiction
+   10 |  99 |      2 | regress_rls_dave  | awesome technology book
+  100 |  55 |      1 | regress_rls_dave  | testing RLS with partitions
+ (11 rows)
+ 
+ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle);
+                      QUERY PLAN                      
+ -----------------------------------------------------
+  Append
+    InitPlan 1 (returns $0)
+      ->  Index Scan using uaccount_pkey on uaccount
+            Index Cond: (pguser = CURRENT_USER)
+    ->  Seq Scan on part_document_fiction
+          Filter: ((dlevel <= $0) AND f_leak(dtitle))
+    ->  Seq Scan on part_document_satire
+          Filter: ((dlevel <= $0) AND f_leak(dtitle))
+    ->  Seq Scan on part_document_nonfiction
+          Filter: ((dlevel <= $0) AND f_leak(dtitle))
+ (10 rows)
+ 
+ -- only owner can change policies
+ ALTER POLICY pp1 ON part_document USING (true);    --fail
+ ERROR:  must be owner of relation part_document
+ DROP POLICY pp1 ON part_document;                  --fail
+ ERROR:  must be owner of relation part_document
+ SET SESSION AUTHORIZATION regress_rls_alice;
+ ALTER POLICY pp1 ON part_document USING (dauthor = current_user);
+ -- viewpoint from regress_rls_bob again
+ SET SESSION AUTHORIZATION regress_rls_bob;
+ SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did;
+ NOTICE:  f_leak => my first novel
+ NOTICE:  f_leak => my second novel
+ NOTICE:  f_leak => my first satire
+ NOTICE:  f_leak => my science textbook
+ NOTICE:  f_leak => my history book
+  did | cid | dlevel |     dauthor     |       dtitle        
+ -----+-----+--------+-----------------+---------------------
+    1 |  11 |      1 | regress_rls_bob | my first novel
+    2 |  11 |      2 | regress_rls_bob | my second novel
+    3 |  99 |      2 | regress_rls_bob | my science textbook
+    4 |  55 |      1 | regress_rls_bob | my first satire
+    5 |  99 |      2 | regress_rls_bob | my history book
+ (5 rows)
+ 
+ -- viewpoint from rls_regres_carol again
+ SET SESSION AUTHORIZATION regress_rls_carol;
+ SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did;
+ NOTICE:  f_leak => great science fiction
+ NOTICE:  f_leak => great satire
+ NOTICE:  f_leak => great technology book
+  did | cid | dlevel |      dauthor      |        dtitle         
+ -----+-----+--------+-------------------+-----------------------
+    6 |  11 |      1 | regress_rls_carol | great science fiction
+    7 |  99 |      2 | regress_rls_carol | great technology book
+    8 |  55 |      2 | regress_rls_carol | great satire
+ (3 rows)
+ 
+ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle);
+                           QUERY PLAN                           
+ ---------------------------------------------------------------
+  Append
+    ->  Seq Scan on part_document_fiction
+          Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
+    ->  Seq Scan on part_document_satire
+          Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
+    ->  Seq Scan on part_document_nonfiction
+          Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle))
+ (7 rows)
+ 
+ -- database superuser does bypass RLS policy when enabled
+ RESET SESSION AUTHORIZATION;
+ SET row_security TO ON;
+ SELECT * FROM part_document ORDER BY did;
+  did | cid | dlevel |      dauthor      |           dtitle            
+ -----+-----+--------+-------------------+-----------------------------
+    1 |  11 |      1 | regress_rls_bob   | my first novel
+    2 |  11 |      2 | regress_rls_bob   | my second novel
+    3 |  99 |      2 | regress_rls_bob   | my science textbook
+    4 |  55 |      1 | regress_rls_bob   | my first satire
+    5 |  99 |      2 | regress_rls_bob   | my history book
+    6 |  11 |      1 | regress_rls_carol | great science fiction
+    7 |  99 |      2 | regress_rls_carol | great technology book
+    8 |  55 |      2 | regress_rls_carol | great satire
+    9 |  11 |      1 | regress_rls_dave  | awesome science fiction
+   10 |  99 |      2 | regress_rls_dave  | awesome technology book
+  100 |  55 |      1 | regress_rls_dave  | testing RLS with partitions
+ (11 rows)
+ 
+ SELECT * FROM part_document_satire ORDER by did;
+  did | cid | dlevel |      dauthor      |           dtitle            
+ -----+-----+--------+-------------------+-----------------------------
+    4 |  55 |      1 | regress_rls_bob   | my first satire
+    8 |  55 |      2 | regress_rls_carol | great satire
+  100 |  55 |      1 | regress_rls_dave  | testing RLS with partitions
+ (3 rows)
+ 
+ -- database non-superuser with bypass privilege can bypass RLS policy when disabled
+ SET SESSION AUTHORIZATION regress_rls_exempt_user;
+ SET row_security TO OFF;
+ SELECT * FROM part_document ORDER BY did;
+  did | cid | dlevel |      dauthor      |           dtitle            
+ -----+-----+--------+-------------------+-----------------------------
+    1 |  11 |      1 | regress_rls_bob   | my first novel
+    2 |  11 |      2 | regress_rls_bob   | my second novel
+    3 |  99 |      2 | regress_rls_bob   | my science textbook
+    4 |  55 |      1 | regress_rls_bob   | my first satire
+    5 |  99 |      2 | regress_rls_bob   | my history book
+    6 |  11 |      1 | regress_rls_carol | great science fiction
+    7 |  99 |      2 | regress_rls_carol | great technology book
+    8 |  55 |      2 | regress_rls_carol | great satire
+    9 |  11 |      1 | regress_rls_dave  | awesome science fiction
+   10 |  99 |      2 | regress_rls_dave  | awesome technology book
+  100 |  55 |      1 | regress_rls_dave  | testing RLS with partitions
+ (11 rows)
+ 
+ SELECT * FROM part_document_satire ORDER by did;
+  did | cid | dlevel |      dauthor      |           dtitle            
+ -----+-----+--------+-------------------+-----------------------------
+    4 |  55 |      1 | regress_rls_bob   | my first satire
+    8 |  55 |      2 | regress_rls_carol | great satire
+  100 |  55 |      1 | regress_rls_dave  | testing RLS with partitions
+ (3 rows)
+ 
+ -- RLS policy does not apply to table owner when RLS enabled.
+ SET SESSION AUTHORIZATION regress_rls_alice;
+ SET row_security TO ON;
+ SELECT * FROM part_document ORDER by did;
+  did | cid | dlevel |      dauthor      |           dtitle            
+ -----+-----+--------+-------------------+-----------------------------
+    1 |  11 |      1 | regress_rls_bob   | my first novel
+    2 |  11 |      2 | regress_rls_bob   | my second novel
+    3 |  99 |      2 | regress_rls_bob   | my science textbook
+    4 |  55 |      1 | regress_rls_bob   | my first satire
+    5 |  99 |      2 | regress_rls_bob   | my history book
+    6 |  11 |      1 | regress_rls_carol | great science fiction
+    7 |  99 |      2 | regress_rls_carol | great technology book
+    8 |  55 |      2 | regress_rls_carol | great satire
+    9 |  11 |      1 | regress_rls_dave  | awesome science fiction
+   10 |  99 |      2 | regress_rls_dave  | awesome technology book
+  100 |  55 |      1 | regress_rls_dave  | testing RLS with partitions
+ (11 rows)
+ 
+ SELECT * FROM part_document_satire ORDER by did;
+  did | cid | dlevel |      dauthor      |           dtitle            
+ -----+-----+--------+-------------------+-----------------------------
+    4 |  55 |      1 | regress_rls_bob   | my first satire
+    8 |  55 |      2 | regress_rls_carol | great satire
+  100 |  55 |      1 | regress_rls_dave  | testing RLS with partitions
+ (3 rows)
+ 
+ -- When RLS disabled, other users get ERROR.
+ SET SESSION AUTHORIZATION regress_rls_dave;
+ SET row_security TO OFF;
+ SELECT * FROM part_document ORDER by did;
+ ERROR:  query would be affected by row-level security policy for table "part_document"
+ SELECT * FROM part_document_satire ORDER by did;
+ ERROR:  query would be affected by row-level security policy for table "part_document_satire"
  ----- Dependencies -----
  SET SESSION AUTHORIZATION regress_rls_alice;
  SET row_security TO ON;
diff --git a/src/test/regress/sql/rowsecurity.sql b/src/test/regress/sql/rowsecurity.sql
index 1b6896e..80537ff 100644
*** a/src/test/regress/sql/rowsecurity.sql
--- b/src/test/regress/sql/rowsecurity.sql
*************** SET row_security TO OFF;
*** 308,313 ****
--- 308,455 ----
  SELECT * FROM t1 WHERE f_leak(b);
  EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b);
  
+ --
+ -- Partitioned Tables
+ --
+ 
+ SET SESSION AUTHORIZATION regress_rls_alice;
+ 
+ CREATE TABLE part_document (
+     did         int,
+     cid         int,
+     dlevel      int not null,
+     dauthor     name,
+     dtitle      text
+ ) PARTITION BY RANGE (cid);
+ GRANT ALL ON part_document TO public;
+ 
+ -- Create partitions for document categories
+ CREATE TABLE part_document_fiction PARTITION OF part_document FOR VALUES FROM (11) to (12);
+ CREATE TABLE part_document_satire PARTITION OF part_document FOR VALUES FROM (55) to (56);
+ CREATE TABLE part_document_nonfiction PARTITION OF part_document FOR VALUES FROM (99) to (100);
+ 
+ GRANT ALL ON part_document_fiction TO public;
+ GRANT ALL ON part_document_satire TO public;
+ GRANT ALL ON part_document_nonfiction TO public;
+ 
+ INSERT INTO part_document VALUES
+     ( 1, 11, 1, 'regress_rls_bob', 'my first novel'),
+     ( 2, 11, 2, 'regress_rls_bob', 'my second novel'),
+     ( 3, 99, 2, 'regress_rls_bob', 'my science textbook'),
+     ( 4, 55, 1, 'regress_rls_bob', 'my first satire'),
+     ( 5, 99, 2, 'regress_rls_bob', 'my history book'),
+     ( 6, 11, 1, 'regress_rls_carol', 'great science fiction'),
+     ( 7, 99, 2, 'regress_rls_carol', 'great technology book'),
+     ( 8, 55, 2, 'regress_rls_carol', 'great satire'),
+     ( 9, 11, 1, 'regress_rls_dave', 'awesome science fiction'),
+     (10, 99, 2, 'regress_rls_dave', 'awesome technology book');
+ 
+ ALTER TABLE part_document ENABLE ROW LEVEL SECURITY;
+ 
+ -- Create policy on parent
+ -- user's security level must be higher than or equal to document's
+ CREATE POLICY pp1 ON part_document AS PERMISSIVE
+     USING (dlevel <= (SELECT seclv FROM uaccount WHERE pguser = current_user));
+ 
+ -- Dave is only allowed to see cid < 55
+ CREATE POLICY pp1r ON part_document AS RESTRICTIVE TO regress_rls_dave
+     USING (cid < 55);
+ 
+ \d+ part_document
+ SELECT * FROM pg_policies WHERE schemaname = 'regress_rls_schema' AND tablename like '%part_document%' ORDER BY policyname;
+ 
+ -- viewpoint from regress_rls_bob
+ SET SESSION AUTHORIZATION regress_rls_bob;
+ SET row_security TO ON;
+ SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did;
+ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle);
+ 
+ -- viewpoint from regress_rls_carol
+ SET SESSION AUTHORIZATION regress_rls_carol;
+ SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did;
+ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle);
+ 
+ -- viewpoint from regress_rls_dave
+ SET SESSION AUTHORIZATION regress_rls_dave;
+ SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did;
+ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle);
+ 
+ -- pp1 ERROR
+ INSERT INTO part_document VALUES (100, 11, 5, 'regress_rls_dave', 'testing pp1'); -- fail
+ -- pp1r ERROR
+ INSERT INTO part_document VALUES (100, 99, 1, 'regress_rls_dave', 'testing pp1r'); -- fail
+ 
+ -- Show that RLS policy does not apply for direct inserts to children
+ -- This should fail with RLS POLICY pp1r violation.
+ INSERT INTO part_document VALUES (100, 55, 1, 'regress_rls_dave', 'testing RLS with partitions'); -- fail
+ -- But this should succeed.
+ INSERT INTO part_document_satire VALUES (100, 55, 1, 'regress_rls_dave', 'testing RLS with partitions'); -- success
+ -- We still cannot see the row using the parent
+ SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did;
+ -- But we can if we look directly
+ SELECT * FROM part_document_satire WHERE f_leak(dtitle) ORDER BY did;
+ 
+ -- Turn on RLS and create policy on child to show RLS is checked before constraints
+ SET SESSION AUTHORIZATION regress_rls_alice;
+ ALTER TABLE part_document_satire ENABLE ROW LEVEL SECURITY;
+ CREATE POLICY pp3 ON part_document_satire AS RESTRICTIVE
+     USING (cid < 55);
+ -- This should fail with RLS violation now.
+ SET SESSION AUTHORIZATION regress_rls_dave;
+ INSERT INTO part_document_satire VALUES (101, 55, 1, 'regress_rls_dave', 'testing RLS with partitions'); -- fail
+ -- And now we cannot see directly into the partition either, due to RLS
+ SELECT * FROM part_document_satire WHERE f_leak(dtitle) ORDER BY did;
+ -- The parent looks same as before
+ -- viewpoint from regress_rls_dave
+ SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did;
+ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle);
+ 
+ -- viewpoint from regress_rls_carol
+ SET SESSION AUTHORIZATION regress_rls_carol;
+ SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did;
+ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle);
+ 
+ -- only owner can change policies
+ ALTER POLICY pp1 ON part_document USING (true);    --fail
+ DROP POLICY pp1 ON part_document;                  --fail
+ 
+ SET SESSION AUTHORIZATION regress_rls_alice;
+ ALTER POLICY pp1 ON part_document USING (dauthor = current_user);
+ 
+ -- viewpoint from regress_rls_bob again
+ SET SESSION AUTHORIZATION regress_rls_bob;
+ SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did;
+ 
+ -- viewpoint from rls_regres_carol again
+ SET SESSION AUTHORIZATION regress_rls_carol;
+ SELECT * FROM part_document WHERE f_leak(dtitle) ORDER BY did;
+ 
+ EXPLAIN (COSTS OFF) SELECT * FROM part_document WHERE f_leak(dtitle);
+ 
+ -- database superuser does bypass RLS policy when enabled
+ RESET SESSION AUTHORIZATION;
+ SET row_security TO ON;
+ SELECT * FROM part_document ORDER BY did;
+ SELECT * FROM part_document_satire ORDER by did;
+ 
+ -- database non-superuser with bypass privilege can bypass RLS policy when disabled
+ SET SESSION AUTHORIZATION regress_rls_exempt_user;
+ SET row_security TO OFF;
+ SELECT * FROM part_document ORDER BY did;
+ SELECT * FROM part_document_satire ORDER by did;
+ 
+ -- RLS policy does not apply to table owner when RLS enabled.
+ SET SESSION AUTHORIZATION regress_rls_alice;
+ SET row_security TO ON;
+ SELECT * FROM part_document ORDER by did;
+ SELECT * FROM part_document_satire ORDER by did;
+ 
+ -- When RLS disabled, other users get ERROR.
+ SET SESSION AUTHORIZATION regress_rls_dave;
+ SET row_security TO OFF;
+ SELECT * FROM part_document ORDER by did;
+ SELECT * FROM part_document_satire ORDER by did;
+ 
  ----- Dependencies -----
  SET SESSION AUTHORIZATION regress_rls_alice;
  SET row_security TO ON;

Attachment: signature.asc
Description: OpenPGP digital signature

Reply via email to