Much restructing of rowsecurity test case
authorPavan Deolasee <[email protected]>
Mon, 28 Aug 2017 09:47:32 +0000 (15:17 +0530)
committerPavan Deolasee <[email protected]>
Mon, 28 Aug 2017 09:47:32 +0000 (15:17 +0530)
- Some problems related to inherited tables fixed by ensuring column ordering.
- ORDER BY clauses added at some other places to ensure consistent row ordering.
- Changes related to TABLESAMPLE accepted as XL returns more rows than PG
- SAVEPOINTs removed and replaced by transaction blocks as XL does not support
  subtransaction
- NOTICEs are not displayed in XL
- Append is pushed down to the remote node now that we impose stricter
  restrictions on inheritance

src/test/regress/expected/rowsecurity.out
src/test/regress/sql/rowsecurity.sql

index a56e6abea364c965f7fd79e08ddebcc7767dce0a..000af55572ed11f91bc9d05d4d7a65aaaa8005cf 100644 (file)
@@ -179,11 +179,10 @@ SELECT * FROM document TABLESAMPLE BERNOULLI(50) REPEATABLE(0)
   WHERE f_leak(dtitle) ORDER BY did;
  did | cid | dlevel |      dauthor      |         dtitle          
 -----+-----+--------+-------------------+-------------------------
-   4 |  44 |      1 | regress_rls_bob   | my first manga
    6 |  22 |      1 | regress_rls_carol | great science fiction
    8 |  44 |      1 | regress_rls_carol | great manga
    9 |  22 |      1 | regress_rls_dave  | awesome science fiction
-(4 rows)
+(3 rows)
 
 -- viewpoint from regress_rls_carol
 SET SESSION AUTHORIZATION regress_rls_carol;
@@ -222,12 +221,11 @@ SELECT * FROM document TABLESAMPLE BERNOULLI(50) REPEATABLE(0)
   WHERE f_leak(dtitle) ORDER BY did;
  did | cid | dlevel |      dauthor      |         dtitle          
 -----+-----+--------+-------------------+-------------------------
-   4 |  44 |      1 | regress_rls_bob   | my first manga
-   5 |  44 |      2 | regress_rls_bob   | my second manga
    6 |  22 |      1 | regress_rls_carol | great science fiction
    8 |  44 |      1 | regress_rls_carol | great manga
    9 |  22 |      1 | regress_rls_dave  | awesome science fiction
-(5 rows)
+  10 |  33 |      2 | regress_rls_dave  | awesome technology book
+(4 rows)
 
 EXPLAIN (COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle);
                             QUERY PLAN                             
@@ -256,16 +254,10 @@ EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dt
                ->  Seq Scan on document
                      Filter: ((dlevel <= $0) AND f_leak(dtitle))
 (11 rows)
+
 -- viewpoint from regress_rls_dave
 SET SESSION AUTHORIZATION regress_rls_dave;
 SELECT * FROM document WHERE f_leak(dtitle) ORDER BY did;
-NOTICE:  f_leak => my first novel
-NOTICE:  f_leak => my second novel
-NOTICE:  f_leak => my science fiction
-NOTICE:  f_leak => great science fiction
-NOTICE:  f_leak => great technology book
-NOTICE:  f_leak => awesome science fiction
-NOTICE:  f_leak => awesome technology book
  did | cid | dlevel |      dauthor      |         dtitle          
 -----+-----+--------+-------------------+-------------------------
    1 |  11 |      1 | regress_rls_bob   | my first novel
@@ -278,13 +270,6 @@ NOTICE:  f_leak => awesome technology book
 (7 rows)
 
 SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle) ORDER BY did;
-NOTICE:  f_leak => my first novel
-NOTICE:  f_leak => my second novel
-NOTICE:  f_leak => my science fiction
-NOTICE:  f_leak => great science fiction
-NOTICE:  f_leak => great technology book
-NOTICE:  f_leak => awesome science fiction
-NOTICE:  f_leak => awesome technology book
  cid | did | dlevel |      dauthor      |         dtitle          |      cname      
 -----+-----+--------+-------------------+-------------------------+-----------------
   11 |   1 |      1 | regress_rls_bob   | my first novel          | novel
@@ -591,285 +576,251 @@ SELECT * FROM category ORDER BY cid;
 --
 SET SESSION AUTHORIZATION regress_rls_alice;
 SET row_security TO ON;
-CREATE TABLE t1 (a int, junk1 text, b text) WITH OIDS;
-ALTER TABLE t1 DROP COLUMN junk1;    -- just a disturbing factor
+-- CREATE TABLE t1 (a int, junk1 text, b text) WITH OIDS;
+-- XL requires columns to be in the same order
+CREATE TABLE t1 (a int, b text) WITH OIDS;
+-- ALTER TABLE t1 DROP COLUMN junk1;    -- just a disturbing factor
 GRANT ALL ON t1 TO public;
 COPY t1 FROM stdin WITH (oids);
 CREATE TABLE t2 (c float) INHERITS (t1);
 GRANT ALL ON t2 TO public;
 COPY t2 FROM stdin WITH (oids);
-CREATE TABLE t3 (c text, b text, a int) WITH OIDS;
+CREATE TABLE t3 (a int, b text) WITH OIDS;
 ALTER TABLE t3 INHERIT t1;
 GRANT ALL ON t3 TO public;
-COPY t3(a,b,c) FROM stdin WITH (oids);
+COPY t3(a,b) FROM stdin WITH (oids);
 CREATE POLICY p1 ON t1 FOR ALL TO PUBLIC USING (a % 2 = 0); -- be even number
 CREATE POLICY p2 ON t2 FOR ALL TO PUBLIC USING (a % 2 = 1); -- be odd number
 ALTER TABLE t1 ENABLE ROW LEVEL SECURITY;
 ALTER TABLE t2 ENABLE ROW LEVEL SECURITY;
 SET SESSION AUTHORIZATION regress_rls_bob;
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
  a |  b  
 ---+-----
  2 | bbb
- 4 | dad
  2 | bcd
- 4 | def
  2 | yyy
+ 4 | dad
+ 4 | def
 (5 rows)
 
 EXPLAIN (COSTS OFF) SELECT * FROM t1;
-                        QUERY PLAN                         
------------------------------------------------------------
- Append
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
+                     QUERY PLAN                      
+-----------------------------------------------------
+ Remote Subquery Scan on all (datanode_1,datanode_2)
+   ->  Append
          ->  Seq Scan on t1
                Filter: ((a % 2) = 0)
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t2
                Filter: ((a % 2) = 0)
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t3
                Filter: ((a % 2) = 0)
-(10 rows)
+(8 rows)
 
-SELECT * FROM t1 WHERE f_leak(b);
-NOTICE:  f_leak => bbb
-NOTICE:  f_leak => dad
-NOTICE:  f_leak => bcd
-NOTICE:  f_leak => def
-NOTICE:  f_leak => yyy
+SELECT * FROM t1 WHERE f_leak(b) ORDER BY a;
  a |  b  
 ---+-----
  2 | bbb
- 4 | dad
  2 | bcd
- 4 | def
  2 | yyy
+ 4 | dad
+ 4 | def
 (5 rows)
 
 EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b);
-                           QUERY PLAN                            
------------------------------------------------------------------
- Subquery Scan on t1
-   Filter: f_leak(t1.b)
+                     QUERY PLAN                      
+-----------------------------------------------------
+ Remote Subquery Scan on all (datanode_1,datanode_2)
    ->  Append
-         ->  Remote Subquery Scan on all (datanode_1,datanode_2)
-               ->  Seq Scan on t1 t1_1
-                     Filter: ((a % 2) = 0)
-         ->  Remote Subquery Scan on all (datanode_1,datanode_2)
-               ->  Seq Scan on t2
-                     Filter: ((a % 2) = 0)
-         ->  Remote Subquery Scan on all (datanode_1,datanode_2)
-               ->  Seq Scan on t3
-                     Filter: ((a % 2) = 0)
-(12 rows)
+         ->  Seq Scan on t1
+               Filter: (((a % 2) = 0) AND f_leak(b))
+         ->  Seq Scan on t2
+               Filter: (((a % 2) = 0) AND f_leak(b))
+         ->  Seq Scan on t3
+               Filter: (((a % 2) = 0) AND f_leak(b))
+(8 rows)
 
 -- reference to system column
-SELECT oid, * FROM t1;
+SELECT oid, * FROM t1 ORDER BY a;
  oid | a |  b  
 -----+---+-----
  102 | 2 | bbb
- 104 | 4 | dad
  202 | 2 | bcd
- 204 | 4 | def
  302 | 2 | yyy
+ 104 | 4 | dad
+ 204 | 4 | def
 (5 rows)
 
 EXPLAIN (COSTS OFF) SELECT *, t1 FROM t1;
-                        QUERY PLAN                         
------------------------------------------------------------
- Append
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
+                     QUERY PLAN                      
+-----------------------------------------------------
+ Remote Subquery Scan on all (datanode_1,datanode_2)
+   ->  Append
          ->  Seq Scan on t1
                Filter: ((a % 2) = 0)
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t2
                Filter: ((a % 2) = 0)
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t3
                Filter: ((a % 2) = 0)
-(10 rows)
+(8 rows)
 
 -- reference to whole-row reference
-SELECT *, t1 FROM t1;
+SELECT *, t1 FROM t1 ORDER BY a;
  a |  b  |   t1    
 ---+-----+---------
  2 | bbb | (2,bbb)
- 4 | dad | (4,dad)
  2 | bcd | (2,bcd)
- 4 | def | (4,def)
  2 | yyy | (2,yyy)
+ 4 | dad | (4,dad)
+ 4 | def | (4,def)
 (5 rows)
 
 EXPLAIN (COSTS OFF) SELECT *, t1 FROM t1;
-                        QUERY PLAN                         
------------------------------------------------------------
- Append
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
+                     QUERY PLAN                      
+-----------------------------------------------------
+ Remote Subquery Scan on all (datanode_1,datanode_2)
+   ->  Append
          ->  Seq Scan on t1
                Filter: ((a % 2) = 0)
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t2
                Filter: ((a % 2) = 0)
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t3
                Filter: ((a % 2) = 0)
-(10 rows)
+(8 rows)
 
 -- for share/update lock
-SELECT * FROM t1 FOR SHARE;
+SELECT * FROM t1 ORDER BY a FOR SHARE;
  a |  b  
 ---+-----
  2 | bbb
- 4 | dad
  2 | bcd
- 4 | def
  2 | yyy
+ 4 | dad
+ 4 | def
 (5 rows)
 
 EXPLAIN (COSTS OFF) SELECT * FROM t1 FOR SHARE;
-                                    QUERY PLAN                                     
------------------------------------------------------------------------------------
- LockRows
-   ->  Subquery Scan on t1
-         ->  LockRows
-               ->  Result
-                     ->  Append
-                           ->  Remote Subquery Scan on all (datanode_1,datanode_2)
-                                 ->  Seq Scan on t1 t1_1
-                                       Filter: ((a % 2) = 0)
-                           ->  Remote Subquery Scan on all (datanode_1,datanode_2)
-                                 ->  Seq Scan on t2
-                                       Filter: ((a % 2) = 0)
-                           ->  Remote Subquery Scan on all (datanode_1,datanode_2)
-                                 ->  Seq Scan on t3
-                                       Filter: ((a % 2) = 0)
-(14 rows)
+                     QUERY PLAN                      
+-----------------------------------------------------
+ Remote Subquery Scan on all (datanode_1,datanode_2)
+   ->  LockRows
+         ->  Append
+               ->  Seq Scan on t1
+                     Filter: ((a % 2) = 0)
+               ->  Seq Scan on t2
+                     Filter: ((a % 2) = 0)
+               ->  Seq Scan on t3
+                     Filter: ((a % 2) = 0)
+(9 rows)
 
-SELECT * FROM t1 WHERE f_leak(b) FOR SHARE;
-NOTICE:  f_leak => bbb
-NOTICE:  f_leak => dad
-NOTICE:  f_leak => bcd
-NOTICE:  f_leak => def
-NOTICE:  f_leak => yyy
+SELECT * FROM t1 WHERE f_leak(b) ORDER BY a FOR SHARE;
  a |  b  
 ---+-----
  2 | bbb
- 4 | dad
  2 | bcd
- 4 | def
  2 | yyy
+ 4 | dad
+ 4 | def
 (5 rows)
 
 EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b) FOR SHARE;
-                                    QUERY PLAN                                     
------------------------------------------------------------------------------------
- LockRows
-   ->  Subquery Scan on t1
-         Filter: f_leak(t1.b)
-         ->  LockRows
-               ->  Result
-                     ->  Append
-                           ->  Remote Subquery Scan on all (datanode_1,datanode_2)
-                                 ->  Seq Scan on t1 t1_1
-                                       Filter: ((a % 2) = 0)
-                           ->  Remote Subquery Scan on all (datanode_1,datanode_2)
-                                 ->  Seq Scan on t2
-                                       Filter: ((a % 2) = 0)
-                           ->  Remote Subquery Scan on all (datanode_1,datanode_2)
-                                 ->  Seq Scan on t3
-                                       Filter: ((a % 2) = 0)
-(15 rows)
+                        QUERY PLAN                         
+-----------------------------------------------------------
+ Remote Subquery Scan on all (datanode_1,datanode_2)
+   ->  LockRows
+         ->  Append
+               ->  Seq Scan on t1
+                     Filter: (((a % 2) = 0) AND f_leak(b))
+               ->  Seq Scan on t2
+                     Filter: (((a % 2) = 0) AND f_leak(b))
+               ->  Seq Scan on t3
+                     Filter: (((a % 2) = 0) AND f_leak(b))
+(9 rows)
 
 -- union all query
 SELECT a, b, oid FROM t2 UNION ALL SELECT a, b, oid FROM t3;
  a |  b  | oid 
 ---+-----+-----
  1 | abc | 201
- 3 | cde | 203
  1 | xxx | 301
  2 | yyy | 302
+ 3 | cde | 203
  3 | zzz | 303
 (5 rows)
 
 EXPLAIN (COSTS OFF) SELECT a, b, oid FROM t2 UNION ALL SELECT a, b, oid FROM t3;
-                        QUERY PLAN                         
------------------------------------------------------------
- Append
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
+                     QUERY PLAN                      
+-----------------------------------------------------
+ Remote Subquery Scan on all (datanode_1,datanode_2)
+   ->  Append
          ->  Seq Scan on t2
                Filter: ((a % 2) = 1)
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t3
-(6 rows)
+(5 rows)
 
 -- superuser is allowed to bypass RLS checks
 RESET SESSION AUTHORIZATION;
 SET row_security TO OFF;
-SELECT * FROM t1 WHERE f_leak(b);
+SELECT * FROM t1 WHERE f_leak(b) ORDER BY a;
  a |  b  
 ---+-----
  1 | aba
- 2 | bbb
- 3 | ccc
- 4 | dad
  1 | abc
- 2 | bcd
- 3 | cde
- 4 | def
  1 | xxx
+ 2 | bbb
+ 2 | bcd
  2 | yyy
+ 3 | ccc
+ 3 | cde
  3 | zzz
+ 4 | dad
+ 4 | def
 (11 rows)
 
 EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b);
-                        QUERY PLAN                         
------------------------------------------------------------
- Append
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
+                     QUERY PLAN                      
+-----------------------------------------------------
+ Remote Subquery Scan on all (datanode_1,datanode_2)
+   ->  Append
          ->  Seq Scan on t1
                Filter: f_leak(b)
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t2
                Filter: f_leak(b)
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t3
                Filter: f_leak(b)
-(10 rows)
+(8 rows)
 
 -- 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 t1 WHERE f_leak(b);
+SELECT * FROM t1 WHERE f_leak(b) ORDER BY a;
  a |  b  
 ---+-----
  1 | aba
- 2 | bbb
- 3 | ccc
- 4 | dad
  1 | abc
- 2 | bcd
- 3 | cde
- 4 | def
  1 | xxx
+ 2 | bbb
+ 2 | bcd
  2 | yyy
+ 3 | ccc
+ 3 | cde
  3 | zzz
+ 4 | dad
+ 4 | def
 (11 rows)
 
 EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b);
-                        QUERY PLAN                         
------------------------------------------------------------
- Append
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
+                     QUERY PLAN                      
+-----------------------------------------------------
+ Remote Subquery Scan on all (datanode_1,datanode_2)
+   ->  Append
          ->  Seq Scan on t1
                Filter: f_leak(b)
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t2
                Filter: f_leak(b)
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t3
                Filter: f_leak(b)
-(10 rows)
+(8 rows)
 
 --
 -- Partitioned Tables
@@ -930,6 +881,8 @@ Policies:
 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)
+Distribute By: HASH(did)
+Location Nodes: ALL DATANODES
 
 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 
@@ -944,10 +897,6 @@ SELECT * FROM pg_policies WHERE schemaname = 'regress_rls_schema' AND tablename
 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
@@ -976,16 +925,6 @@ 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;
-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
@@ -1020,10 +959,6 @@ 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;
-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
@@ -1059,10 +994,6 @@ ERROR:  new row violates row-level security policy "pp1r" for table "part_docume
 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
@@ -1073,9 +1004,6 @@ NOTICE:  f_leak => awesome science fiction
 
 -- 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
@@ -1101,10 +1029,6 @@ 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;
-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
@@ -1129,17 +1053,6 @@ 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;
-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
@@ -1182,11 +1095,6 @@ 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
@@ -1199,9 +1107,6 @@ NOTICE:  f_leak => my history book
 -- 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
@@ -1382,7 +1287,6 @@ ERROR:  infinite recursion detected in policy for relation "rec1"
 SET SESSION AUTHORIZATION regress_rls_bob;
 \set VERBOSITY terse \\ -- suppress cascade details
 DROP VIEW rec1v, rec2v CASCADE;
-NOTICE:  drop cascades to 2 other objects
 \set VERBOSITY default
 CREATE VIEW rec1v WITH (security_barrier) AS SELECT * FROM rec1;
 CREATE VIEW rec2v WITH (security_barrier) AS SELECT * FROM rec2;
@@ -1502,53 +1406,49 @@ EXECUTE p1(2);
 (3 rows)
 
 EXPLAIN (COSTS OFF) EXECUTE p1(2);
-                        QUERY PLAN                         
------------------------------------------------------------
- Append
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
+                     QUERY PLAN                      
+-----------------------------------------------------
+ Remote Subquery Scan on all (datanode_1,datanode_2)
+   ->  Append
          ->  Seq Scan on t1
                Filter: ((a <= 2) AND ((a % 2) = 0))
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t2
                Filter: ((a <= 2) AND ((a % 2) = 0))
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t3
                Filter: ((a <= 2) AND ((a % 2) = 0))
-(10 rows)
+(8 rows)
 
 -- superuser is allowed to bypass RLS checks
 RESET SESSION AUTHORIZATION;
 SET row_security TO OFF;
-SELECT * FROM t1 WHERE f_leak(b);
+SELECT * FROM t1 WHERE f_leak(b) ORDER BY a;
  a |  b  
 ---+-----
  1 | aba
- 2 | bbb
- 3 | ccc
- 4 | dad
  1 | abc
- 2 | bcd
- 3 | cde
- 4 | def
  1 | xxx
+ 2 | bbb
+ 2 | bcd
  2 | yyy
+ 3 | ccc
+ 3 | cde
  3 | zzz
+ 4 | dad
+ 4 | def
 (11 rows)
 
 EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b);
-                        QUERY PLAN                         
------------------------------------------------------------
- Append
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
+                     QUERY PLAN                      
+-----------------------------------------------------
+ Remote Subquery Scan on all (datanode_1,datanode_2)
+   ->  Append
          ->  Seq Scan on t1
                Filter: f_leak(b)
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t2
                Filter: f_leak(b)
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t3
                Filter: f_leak(b)
-(10 rows)
+(8 rows)
 
 -- plan cache should be invalidated
 EXECUTE p1(2);
@@ -1563,19 +1463,17 @@ EXECUTE p1(2);
 (6 rows)
 
 EXPLAIN (COSTS OFF) EXECUTE p1(2);
-                        QUERY PLAN                         
------------------------------------------------------------
- Append
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
+                     QUERY PLAN                      
+-----------------------------------------------------
+ Remote Subquery Scan on all (datanode_1,datanode_2)
+   ->  Append
          ->  Seq Scan on t1
                Filter: (a <= 2)
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t2
                Filter: (a <= 2)
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t3
                Filter: (a <= 2)
-(10 rows)
+(8 rows)
 
 PREPARE p2(int) AS SELECT * FROM t1 WHERE a = $1;
 EXECUTE p2(2);
@@ -1587,19 +1485,17 @@ EXECUTE p2(2);
 (3 rows)
 
 EXPLAIN (COSTS OFF) EXECUTE p2(2);
-                        QUERY PLAN                         
------------------------------------------------------------
- Append
-   ->  Remote Subquery Scan on all (datanode_1)
+                QUERY PLAN                
+------------------------------------------
+ Remote Subquery Scan on all (datanode_1)
+   ->  Append
          ->  Seq Scan on t1
                Filter: (a = 2)
-   ->  Remote Subquery Scan on all (datanode_1)
          ->  Seq Scan on t2
                Filter: (a = 2)
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t3
                Filter: (a = 2)
-(10 rows)
+(8 rows)
 
 -- also, case when privilege switch from superuser
 SET SESSION AUTHORIZATION regress_rls_bob;
@@ -1613,19 +1509,17 @@ EXECUTE p2(2);
 (3 rows)
 
 EXPLAIN (COSTS OFF) EXECUTE p2(2);
-                        QUERY PLAN                         
------------------------------------------------------------
- Append
-   ->  Remote Subquery Scan on all (datanode_1)
+                    QUERY PLAN                     
+---------------------------------------------------
+ Remote Subquery Scan on all (datanode_1)
+   ->  Append
          ->  Seq Scan on t1
                Filter: ((a = 2) AND ((a % 2) = 0))
-   ->  Remote Subquery Scan on all (datanode_1)
          ->  Seq Scan on t2
                Filter: ((a = 2) AND ((a % 2) = 0))
-   ->  Remote Subquery Scan on all (datanode_1,datanode_2)
          ->  Seq Scan on t3
                Filter: ((a = 2) AND ((a % 2) = 0))
-(10 rows)
+(8 rows)
 
 --
 -- UPDATE / DELETE and Row-level security
@@ -1635,39 +1529,27 @@ EXPLAIN (COSTS OFF) UPDATE t1 SET b = b || b WHERE f_leak(b);
                      QUERY PLAN                      
 -----------------------------------------------------
  Remote Subquery Scan on all (datanode_1,datanode_2)
-   ->  Update on t1 t1_3
-         Update on t1 t1_3
-         Update on t2 t1
-         Update on t3 t1
-         ->  Subquery Scan on t1
-               Filter: f_leak(t1.b)
-               ->  LockRows
-                     ->  Seq Scan on t1 t1_4
-                           Filter: ((a % 2) = 0)
-         ->  Subquery Scan on t1_1
-               Filter: f_leak(t1_1.b)
-               ->  LockRows
-                     ->  Seq Scan on t2
-                           Filter: ((a % 2) = 0)
-         ->  Subquery Scan on t1_2
-               Filter: f_leak(t1_2.b)
-               ->  LockRows
-                     ->  Seq Scan on t3
-                           Filter: ((a % 2) = 0)
-(20 rows)
+   ->  Update on t1
+         Update on t1
+         Update on t2
+         Update on t3
+         ->  Seq Scan on t1
+               Filter: (((a % 2) = 0) AND f_leak(b))
+         ->  Seq Scan on t2
+               Filter: (((a % 2) = 0) AND f_leak(b))
+         ->  Seq Scan on t3
+               Filter: (((a % 2) = 0) AND f_leak(b))
+(11 rows)
 
 UPDATE t1 SET b = b || b WHERE f_leak(b);
 EXPLAIN (COSTS OFF) UPDATE only t1 SET b = b || '_updt' WHERE f_leak(b);
                      QUERY PLAN                      
 -----------------------------------------------------
  Remote Subquery Scan on all (datanode_1,datanode_2)
-   ->  Update on t1 t1_1
-         ->  Subquery Scan on t1
-               Filter: f_leak(t1.b)
-               ->  LockRows
-                     ->  Seq Scan on t1 t1_2
-                           Filter: ((a % 2) = 0)
-(7 rows)
+   ->  Update on t1
+         ->  Seq Scan on t1
+               Filter: (((a % 2) = 0) AND f_leak(b))
+(4 rows)
 
 UPDATE only t1 SET b = b || '_updt' WHERE f_leak(b);
 -- returning clause with system column
@@ -1768,38 +1650,26 @@ EXPLAIN (COSTS OFF) DELETE FROM only t1 WHERE f_leak(b);
                      QUERY PLAN                      
 -----------------------------------------------------
  Remote Subquery Scan on all (datanode_1,datanode_2)
-   ->  Delete on t1 t1_1
-         ->  Subquery Scan on t1
-               Filter: f_leak(t1.b)
-               ->  LockRows
-                     ->  Seq Scan on t1 t1_2
-                           Filter: ((a % 2) = 0)
-(7 rows)
+   ->  Delete on t1
+         ->  Seq Scan on t1
+               Filter: (((a % 2) = 0) AND f_leak(b))
+(4 rows)
 
 EXPLAIN (COSTS OFF) DELETE FROM t1 WHERE f_leak(b);
                      QUERY PLAN                      
 -----------------------------------------------------
  Remote Subquery Scan on all (datanode_1,datanode_2)
-   ->  Delete on t1 t1_3
-         Delete on t1 t1_3
-         Delete on t2 t1
-         Delete on t3 t1
-         ->  Subquery Scan on t1
-               Filter: f_leak(t1.b)
-               ->  LockRows
-                     ->  Seq Scan on t1 t1_4
-                           Filter: ((a % 2) = 0)
-         ->  Subquery Scan on t1_1
-               Filter: f_leak(t1_1.b)
-               ->  LockRows
-                     ->  Seq Scan on t2
-                           Filter: ((a % 2) = 0)
-         ->  Subquery Scan on t1_2
-               Filter: f_leak(t1_2.b)
-               ->  LockRows
-                     ->  Seq Scan on t3
-                           Filter: ((a % 2) = 0)
-(20 rows)
+   ->  Delete on t1
+         Delete on t1
+         Delete on t2
+         Delete on t3
+         ->  Seq Scan on t1
+               Filter: (((a % 2) = 0) AND f_leak(b))
+         ->  Seq Scan on t2
+               Filter: (((a % 2) = 0) AND f_leak(b))
+         ->  Seq Scan on t3
+               Filter: (((a % 2) = 0) AND f_leak(b))
+(11 rows)
 
 DELETE FROM only t1 WHERE f_leak(b) RETURNING oid, *, t1;
  oid | a |      b      |       t1        
@@ -1855,31 +1725,23 @@ INSERT INTO bv1 VALUES (11, 'xxx'); -- should fail RLS check
 ERROR:  new row violates row-level security policy for table "b1"
 INSERT INTO bv1 VALUES (12, 'xxx'); -- ok
 EXPLAIN (COSTS OFF) UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b);
-                                   QUERY PLAN                                    
----------------------------------------------------------------------------------
+                                 QUERY PLAN                                  
+-----------------------------------------------------------------------------
  Remote Subquery Scan on all (datanode_2)
-   ->  Update on b1 b1_1
-         ->  Subquery Scan on b1
-               Filter: f_leak(b1.b)
-               ->  Subquery Scan on b1_2
-                     ->  LockRows
-                           ->  Seq Scan on b1 b1_3
-                                 Filter: ((a > 0) AND (a = 4) AND ((a % 2) = 0))
-(8 rows)
+   ->  Update on b1
+         ->  Seq Scan on b1
+               Filter: ((a > 0) AND (a = 4) AND ((a % 2) = 0) AND f_leak(b))
+(4 rows)
 
 UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b);
 EXPLAIN (COSTS OFF) DELETE FROM bv1 WHERE a = 6 AND f_leak(b);
-                                   QUERY PLAN                                    
----------------------------------------------------------------------------------
+                                 QUERY PLAN                                  
+-----------------------------------------------------------------------------
  Remote Subquery Scan on all (datanode_1)
-   ->  Delete on b1 b1_1
-         ->  Subquery Scan on b1
-               Filter: f_leak(b1.b)
-               ->  Subquery Scan on b1_2
-                     ->  LockRows
-                           ->  Seq Scan on b1 b1_3
-                                 Filter: ((a > 0) AND (a = 6) AND ((a % 2) = 0))
-(8 rows)
+   ->  Delete on b1
+         ->  Seq Scan on b1
+               Filter: ((a > 0) AND (a = 6) AND ((a % 2) = 0) AND f_leak(b))
+(4 rows)
 
 DELETE FROM bv1 WHERE a = 6 AND f_leak(b);
 SET SESSION AUTHORIZATION regress_rls_alice;
@@ -3169,70 +3031,28 @@ FETCH ABSOLUTE 1 FROM current_check_cursor;
 
 -- Still cannot UPDATE row 2 through cursor
 UPDATE current_check SET payload = payload || '_new' WHERE CURRENT OF current_check_cursor RETURNING *;
- currentid | payload | rlsuser 
------------+---------+---------
-(0 rows)
-
+ERROR:  WHERE CURRENT OF clause not yet supported
 -- Can update row 4 through cursor, which is the next visible row
 FETCH RELATIVE 1 FROM current_check_cursor;
- currentid | payload |     rlsuser     
------------+---------+-----------------
-         4 | def     | regress_rls_bob
-(1 row)
-
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
 UPDATE current_check SET payload = payload || '_new' WHERE CURRENT OF current_check_cursor RETURNING *;
- currentid | payload |     rlsuser     
------------+---------+-----------------
-         4 | def_new | regress_rls_bob
-(1 row)
-
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
 SELECT * FROM current_check;
- currentid | payload |     rlsuser     
------------+---------+-----------------
-         2 | bcd     | regress_rls_bob
-         4 | def_new | regress_rls_bob
-(2 rows)
-
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
 -- Plan should be a subquery TID scan
 EXPLAIN (COSTS OFF) UPDATE current_check SET payload = payload WHERE CURRENT OF current_check_cursor;
-                         QUERY PLAN                          
--------------------------------------------------------------
- Update on current_check
-   ->  Tid Scan on current_check
-         TID Cond: CURRENT OF current_check_cursor
-         Filter: ((currentid = 4) AND ((currentid % 2) = 0))
-(4 rows)
-
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
 -- Similarly can only delete row 4
 FETCH ABSOLUTE 1 FROM current_check_cursor;
- currentid | payload |     rlsuser     
------------+---------+-----------------
-         2 | bcd     | regress_rls_bob
-(1 row)
-
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
 DELETE FROM current_check WHERE CURRENT OF current_check_cursor RETURNING *;
- currentid | payload | rlsuser 
------------+---------+---------
-(0 rows)
-
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
 FETCH RELATIVE 1 FROM current_check_cursor;
- currentid | payload |     rlsuser     
------------+---------+-----------------
-         4 | def     | regress_rls_bob
-(1 row)
-
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
 DELETE FROM current_check WHERE CURRENT OF current_check_cursor RETURNING *;
- currentid | payload |     rlsuser     
------------+---------+-----------------
-         4 | def_new | regress_rls_bob
-(1 row)
-
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
 SELECT * FROM current_check;
- currentid | payload |     rlsuser     
------------+---------+-----------------
-         2 | bcd     | regress_rls_bob
-(1 row)
-
+ERROR:  current transaction is aborted, commands ignored until end of transaction block
 COMMIT;
 --
 -- check pg_stats view filtering
@@ -3323,31 +3143,130 @@ SELECT refclassid::regclass, deptype
  pg_authid  | r
 (2 rows)
 
-SAVEPOINT q;
 DROP ROLE regress_rls_eve; --fails due to dependency on POLICY p
 ERROR:  role "regress_rls_eve" cannot be dropped because some objects depend on it
 DETAIL:  target of policy p on table tbl1
 privileges for table tbl1
-ROLLBACK TO q;
+ROLLBACK;
+BEGIN;
+CREATE ROLE regress_rls_eve;
+CREATE ROLE regress_rls_frank;
+CREATE TABLE tbl1 (c) AS VALUES ('bar'::text);
+GRANT SELECT ON TABLE tbl1 TO regress_rls_eve;
+CREATE POLICY P ON tbl1 TO regress_rls_eve, regress_rls_frank USING (true);
+SELECT refclassid::regclass, deptype
+  FROM pg_depend
+  WHERE classid = 'pg_policy'::regclass
+  AND refobjid = 'tbl1'::regclass;
+ refclassid | deptype 
+------------+---------
+ pg_class   | a
+(1 row)
+
+SELECT refclassid::regclass, deptype
+  FROM pg_shdepend
+  WHERE classid = 'pg_policy'::regclass
+  AND refobjid IN ('regress_rls_eve'::regrole, 'regress_rls_frank'::regrole);
+ refclassid | deptype 
+------------+---------
+ pg_authid  | r
+ pg_authid  | r
+(2 rows)
+
 ALTER POLICY p ON tbl1 TO regress_rls_frank USING (true);
-SAVEPOINT q;
 DROP ROLE regress_rls_eve; --fails due to dependency on GRANT SELECT
 ERROR:  role "regress_rls_eve" cannot be dropped because some objects depend on it
 DETAIL:  privileges for table tbl1
-ROLLBACK TO q;
+ROLLBACK;
+BEGIN;
+CREATE ROLE regress_rls_eve;
+CREATE ROLE regress_rls_frank;
+CREATE TABLE tbl1 (c) AS VALUES ('bar'::text);
+GRANT SELECT ON TABLE tbl1 TO regress_rls_eve;
+CREATE POLICY P ON tbl1 TO regress_rls_eve, regress_rls_frank USING (true);
+SELECT refclassid::regclass, deptype
+  FROM pg_depend
+  WHERE classid = 'pg_policy'::regclass
+  AND refobjid = 'tbl1'::regclass;
+ refclassid | deptype 
+------------+---------
+ pg_class   | a
+(1 row)
+
+SELECT refclassid::regclass, deptype
+  FROM pg_shdepend
+  WHERE classid = 'pg_policy'::regclass
+  AND refobjid IN ('regress_rls_eve'::regrole, 'regress_rls_frank'::regrole);
+ refclassid | deptype 
+------------+---------
+ pg_authid  | r
+ pg_authid  | r
+(2 rows)
+
+ALTER POLICY p ON tbl1 TO regress_rls_frank USING (true);
 REVOKE ALL ON TABLE tbl1 FROM regress_rls_eve;
-SAVEPOINT q;
 DROP ROLE regress_rls_eve; --succeeds
-ROLLBACK TO q;
-SAVEPOINT q;
+ROLLBACK;
+BEGIN;
+CREATE ROLE regress_rls_eve;
+CREATE ROLE regress_rls_frank;
+CREATE TABLE tbl1 (c) AS VALUES ('bar'::text);
+GRANT SELECT ON TABLE tbl1 TO regress_rls_eve;
+CREATE POLICY P ON tbl1 TO regress_rls_eve, regress_rls_frank USING (true);
+SELECT refclassid::regclass, deptype
+  FROM pg_depend
+  WHERE classid = 'pg_policy'::regclass
+  AND refobjid = 'tbl1'::regclass;
+ refclassid | deptype 
+------------+---------
+ pg_class   | a
+(1 row)
+
+SELECT refclassid::regclass, deptype
+  FROM pg_shdepend
+  WHERE classid = 'pg_policy'::regclass
+  AND refobjid IN ('regress_rls_eve'::regrole, 'regress_rls_frank'::regrole);
+ refclassid | deptype 
+------------+---------
+ pg_authid  | r
+ pg_authid  | r
+(2 rows)
+
+ALTER POLICY p ON tbl1 TO regress_rls_frank USING (true);
+REVOKE ALL ON TABLE tbl1 FROM regress_rls_eve;
 DROP ROLE regress_rls_frank; --fails due to dependency on POLICY p
 ERROR:  role "regress_rls_frank" cannot be dropped because some objects depend on it
 DETAIL:  target of policy p on table tbl1
-ROLLBACK TO q;
+ROLLBACK;
+BEGIN;
+CREATE ROLE regress_rls_eve;
+CREATE ROLE regress_rls_frank;
+CREATE TABLE tbl1 (c) AS VALUES ('bar'::text);
+GRANT SELECT ON TABLE tbl1 TO regress_rls_eve;
+CREATE POLICY P ON tbl1 TO regress_rls_eve, regress_rls_frank USING (true);
+SELECT refclassid::regclass, deptype
+  FROM pg_depend
+  WHERE classid = 'pg_policy'::regclass
+  AND refobjid = 'tbl1'::regclass;
+ refclassid | deptype 
+------------+---------
+ pg_class   | a
+(1 row)
+
+SELECT refclassid::regclass, deptype
+  FROM pg_shdepend
+  WHERE classid = 'pg_policy'::regclass
+  AND refobjid IN ('regress_rls_eve'::regrole, 'regress_rls_frank'::regrole);
+ refclassid | deptype 
+------------+---------
+ pg_authid  | r
+ pg_authid  | r
+(2 rows)
+
+ALTER POLICY p ON tbl1 TO regress_rls_frank USING (true);
+REVOKE ALL ON TABLE tbl1 FROM regress_rls_eve;
 DROP POLICY p ON tbl1;
-SAVEPOINT q;
 DROP ROLE regress_rls_frank; -- succeeds
-ROLLBACK TO q;
 ROLLBACK; -- cleanup
 --
 -- Converting table to view
@@ -3356,27 +3275,27 @@ BEGIN;
 CREATE TABLE t (c int);
 CREATE POLICY p ON t USING (c % 2 = 1);
 ALTER TABLE t ENABLE ROW LEVEL SECURITY;
-SAVEPOINT q;
-ERROR:  SAVEPOINT is not yet supported.
 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:  current transaction is aborted, commands ignored until end of transaction block
-ROLLBACK TO q;
-ERROR:  no such savepoint
+ERROR:  could not convert table "t" to a view because it has row security enabled
+ROLLBACK;
+BEGIN;
+CREATE TABLE t (c int);
+CREATE POLICY p ON t USING (c % 2 = 1);
+ALTER TABLE t ENABLE ROW LEVEL SECURITY;
 ALTER TABLE t DISABLE ROW LEVEL SECURITY;
-ERROR:  current transaction is aborted, commands ignored until end of transaction block
-SAVEPOINT q;
-ERROR:  current transaction is aborted, commands ignored until end of transaction block
 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:  current transaction is aborted, commands ignored until end of transaction block
-ROLLBACK TO q;
-ERROR:  no such savepoint
+ERROR:  could not convert table "t" to a view because it has row security policies
+ROLLBACK;
+BEGIN;
+CREATE TABLE t (c int);
+CREATE POLICY p ON t USING (c % 2 = 1);
+ALTER TABLE t ENABLE ROW LEVEL SECURITY;
+ALTER TABLE t DISABLE ROW LEVEL SECURITY;
 DROP POLICY p ON t;
-ERROR:  current transaction is aborted, commands ignored until end of transaction block
 CREATE RULE "_RETURN" AS ON SELECT TO t DO INSTEAD
   SELECT * FROM generate_series(1,5) t0(c); -- succeeds
-ERROR:  current transaction is aborted, commands ignored until end of transaction block
 ROLLBACK;
 --
 -- Policy expression handling
index 65e91583d4689e0420439af8f1f22a329d7d2ad0..c0bf77938480379ddad03cef8bbc7284261e4a35 100644 (file)
@@ -203,7 +203,7 @@ UPDATE document SET did = 8, dauthor = 'regress_rls_carol' WHERE did = 5; -- Sho
 RESET SESSION AUTHORIZATION;
 SET row_security TO ON;
 SELECT * FROM document ORDER BY did;
-SELECT * FROM category;
+SELECT * FROM category ORDER BY cid;
 
 -- database superuser does bypass RLS policy when disabled
 RESET SESSION AUTHORIZATION;
@@ -236,8 +236,10 @@ SET SESSION AUTHORIZATION regress_rls_alice;
 
 SET row_security TO ON;
 
-CREATE TABLE t1 (a int, junk1 text, b text) WITH OIDS;
-ALTER TABLE t1 DROP COLUMN junk1;    -- just a disturbing factor
+-- CREATE TABLE t1 (a int, junk1 text, b text) WITH OIDS;
+-- XL requires columns to be in the same order
+CREATE TABLE t1 (a int, b text) WITH OIDS;
+-- ALTER TABLE t1 DROP COLUMN junk1;    -- just a disturbing factor
 GRANT ALL ON t1 TO public;
 
 COPY t1 FROM stdin WITH (oids);
@@ -257,14 +259,14 @@ COPY t2 FROM stdin WITH (oids);
 204    4       def     4.4
 \.
 
-CREATE TABLE t3 (c text, b text, a int) WITH OIDS;
+CREATE TABLE t3 (a int, b text) WITH OIDS;
 ALTER TABLE t3 INHERIT t1;
 GRANT ALL ON t3 TO public;
 
-COPY t3(a,b,c) FROM stdin WITH (oids);
-301    1       xxx     X
-302    2       yyy     Y
-303    3       zzz     Z
+COPY t3(a,b) FROM stdin WITH (oids);
+301    1       xxx
+302    2       yyy
+303    3       zzz
 \.
 
 CREATE POLICY p1 ON t1 FOR ALL TO PUBLIC USING (a % 2 = 0); -- be even number
@@ -275,25 +277,25 @@ ALTER TABLE t2 ENABLE ROW LEVEL SECURITY;
 
 SET SESSION AUTHORIZATION regress_rls_bob;
 
-SELECT * FROM t1;
+SELECT * FROM t1 ORDER BY a;
 EXPLAIN (COSTS OFF) SELECT * FROM t1;
 
-SELECT * FROM t1 WHERE f_leak(b);
+SELECT * FROM t1 WHERE f_leak(b) ORDER BY a;
 EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b);
 
 -- reference to system column
-SELECT oid, * FROM t1;
+SELECT oid, * FROM t1 ORDER BY a;
 EXPLAIN (COSTS OFF) SELECT *, t1 FROM t1;
 
 -- reference to whole-row reference
-SELECT *, t1 FROM t1;
+SELECT *, t1 FROM t1 ORDER BY a;
 EXPLAIN (COSTS OFF) SELECT *, t1 FROM t1;
 
 -- for share/update lock
-SELECT * FROM t1 FOR SHARE;
+SELECT * FROM t1 ORDER BY a FOR SHARE;
 EXPLAIN (COSTS OFF) SELECT * FROM t1 FOR SHARE;
 
-SELECT * FROM t1 WHERE f_leak(b) FOR SHARE;
+SELECT * FROM t1 WHERE f_leak(b) ORDER BY a FOR SHARE;
 EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b) FOR SHARE;
 
 -- union all query
@@ -303,13 +305,13 @@ EXPLAIN (COSTS OFF) SELECT a, b, oid FROM t2 UNION ALL SELECT a, b, oid FROM t3;
 -- superuser is allowed to bypass RLS checks
 RESET SESSION AUTHORIZATION;
 SET row_security TO OFF;
-SELECT * FROM t1 WHERE f_leak(b);
+SELECT * FROM t1 WHERE f_leak(b) ORDER BY a;
 EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b);
 
 -- 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 t1 WHERE f_leak(b);
+SELECT * FROM t1 WHERE f_leak(b) ORDER BY a;
 EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b);
 
 --
@@ -590,7 +592,7 @@ EXPLAIN (COSTS OFF) EXECUTE p1(2);
 -- superuser is allowed to bypass RLS checks
 RESET SESSION AUTHORIZATION;
 SET row_security TO OFF;
-SELECT * FROM t1 WHERE f_leak(b);
+SELECT * FROM t1 WHERE f_leak(b) ORDER BY a;
 EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b);
 
 -- plan cache should be invalidated
@@ -1417,29 +1419,87 @@ SELECT refclassid::regclass, deptype
   WHERE classid = 'pg_policy'::regclass
   AND refobjid IN ('regress_rls_eve'::regrole, 'regress_rls_frank'::regrole);
 
-SAVEPOINT q;
 DROP ROLE regress_rls_eve; --fails due to dependency on POLICY p
-ROLLBACK TO q;
+ROLLBACK;
+
+BEGIN;
+CREATE ROLE regress_rls_eve;
+CREATE ROLE regress_rls_frank;
+CREATE TABLE tbl1 (c) AS VALUES ('bar'::text);
+GRANT SELECT ON TABLE tbl1 TO regress_rls_eve;
+CREATE POLICY P ON tbl1 TO regress_rls_eve, regress_rls_frank USING (true);
+SELECT refclassid::regclass, deptype
+  FROM pg_depend
+  WHERE classid = 'pg_policy'::regclass
+  AND refobjid = 'tbl1'::regclass;
+SELECT refclassid::regclass, deptype
+  FROM pg_shdepend
+  WHERE classid = 'pg_policy'::regclass
+  AND refobjid IN ('regress_rls_eve'::regrole, 'regress_rls_frank'::regrole);
 
 ALTER POLICY p ON tbl1 TO regress_rls_frank USING (true);
-SAVEPOINT q;
 DROP ROLE regress_rls_eve; --fails due to dependency on GRANT SELECT
-ROLLBACK TO q;
+ROLLBACK;
+
+BEGIN;
+CREATE ROLE regress_rls_eve;
+CREATE ROLE regress_rls_frank;
+CREATE TABLE tbl1 (c) AS VALUES ('bar'::text);
+GRANT SELECT ON TABLE tbl1 TO regress_rls_eve;
+CREATE POLICY P ON tbl1 TO regress_rls_eve, regress_rls_frank USING (true);
+SELECT refclassid::regclass, deptype
+  FROM pg_depend
+  WHERE classid = 'pg_policy'::regclass
+  AND refobjid = 'tbl1'::regclass;
+SELECT refclassid::regclass, deptype
+  FROM pg_shdepend
+  WHERE classid = 'pg_policy'::regclass
+  AND refobjid IN ('regress_rls_eve'::regrole, 'regress_rls_frank'::regrole);
 
+ALTER POLICY p ON tbl1 TO regress_rls_frank USING (true);
 REVOKE ALL ON TABLE tbl1 FROM regress_rls_eve;
-SAVEPOINT q;
 DROP ROLE regress_rls_eve; --succeeds
-ROLLBACK TO q;
+ROLLBACK;
+
+BEGIN;
+CREATE ROLE regress_rls_eve;
+CREATE ROLE regress_rls_frank;
+CREATE TABLE tbl1 (c) AS VALUES ('bar'::text);
+GRANT SELECT ON TABLE tbl1 TO regress_rls_eve;
+CREATE POLICY P ON tbl1 TO regress_rls_eve, regress_rls_frank USING (true);
+SELECT refclassid::regclass, deptype
+  FROM pg_depend
+  WHERE classid = 'pg_policy'::regclass
+  AND refobjid = 'tbl1'::regclass;
+SELECT refclassid::regclass, deptype
+  FROM pg_shdepend
+  WHERE classid = 'pg_policy'::regclass
+  AND refobjid IN ('regress_rls_eve'::regrole, 'regress_rls_frank'::regrole);
 
-SAVEPOINT q;
+ALTER POLICY p ON tbl1 TO regress_rls_frank USING (true);
+REVOKE ALL ON TABLE tbl1 FROM regress_rls_eve;
 DROP ROLE regress_rls_frank; --fails due to dependency on POLICY p
-ROLLBACK TO q;
+ROLLBACK;
+
+BEGIN;
+CREATE ROLE regress_rls_eve;
+CREATE ROLE regress_rls_frank;
+CREATE TABLE tbl1 (c) AS VALUES ('bar'::text);
+GRANT SELECT ON TABLE tbl1 TO regress_rls_eve;
+CREATE POLICY P ON tbl1 TO regress_rls_eve, regress_rls_frank USING (true);
+SELECT refclassid::regclass, deptype
+  FROM pg_depend
+  WHERE classid = 'pg_policy'::regclass
+  AND refobjid = 'tbl1'::regclass;
+SELECT refclassid::regclass, deptype
+  FROM pg_shdepend
+  WHERE classid = 'pg_policy'::regclass
+  AND refobjid IN ('regress_rls_eve'::regrole, 'regress_rls_frank'::regrole);
 
+ALTER POLICY p ON tbl1 TO regress_rls_frank USING (true);
+REVOKE ALL ON TABLE tbl1 FROM regress_rls_eve;
 DROP POLICY p ON tbl1;
-SAVEPOINT q;
 DROP ROLE regress_rls_frank; -- succeeds
-ROLLBACK TO q;
-
 ROLLBACK; -- cleanup
 
 --
@@ -1449,18 +1509,24 @@ BEGIN;
 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;
+ROLLBACK;
 
+BEGIN;
+CREATE TABLE t (c int);
+CREATE POLICY p ON t USING (c % 2 = 1);
+ALTER TABLE t ENABLE ROW LEVEL SECURITY;
 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;
+ROLLBACK;
 
+BEGIN;
+CREATE TABLE t (c int);
+CREATE POLICY p ON t USING (c % 2 = 1);
+ALTER TABLE t ENABLE ROW LEVEL SECURITY;
+ALTER TABLE t DISABLE ROW LEVEL SECURITY;
 DROP POLICY p ON t;
 CREATE RULE "_RETURN" AS ON SELECT TO t DO INSTEAD
   SELECT * FROM generate_series(1,5) t0(c); -- succeeds