Collect the global OR of hasRowSecurity flags for plancache
authorStephen Frost <sfrost@snowman.net>
Tue, 15 Dec 2015 01:05:43 +0000 (20:05 -0500)
committerStephen Frost <sfrost@snowman.net>
Tue, 15 Dec 2015 01:05:43 +0000 (20:05 -0500)
We carry around information about if a given query has row security or
not to allow the plancache to use that information to invalidate a
planned query in the event that the environment changes.

Previously, the flag of one of the subqueries was simply being copied
into place to indicate if the query overall included RLS components.
That's wrong as we need the global OR of all subqueries.  Fix by
changing the code to match how fireRIRules works, which is results
in OR'ing all of the flags.

Noted by Tom.

Back-patch to 9.5 where RLS was introduced.

src/backend/optimizer/plan/planner.c
src/backend/optimizer/plan/setrefs.c
src/test/regress/expected/rowsecurity.out
src/test/regress/sql/rowsecurity.sql

index 797df31c883fa994bdf95b25e407abbc13527dc3..2c04f5c994df36827d6c382d8e37f891de274f90 100644 (file)
@@ -1529,7 +1529,8 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
         * This may add new security barrier subquery RTEs to the rangetable.
         */
        expand_security_quals(root, tlist);
-       root->glob->hasRowSecurity = parse->hasRowSecurity;
+       if (parse->hasRowSecurity)
+           root->glob->hasRowSecurity = true;
 
        /*
         * Locate any window functions in the tlist.  (We don't need to look
index d2232c227bcfddf8d987421d9a2ac0fff6e8da54..12e929068a70f28a9ceb9b296fffc33b924725da 100644 (file)
@@ -2401,7 +2401,8 @@ extract_query_dependencies_walker(Node *node, PlannerInfo *context)
        ListCell   *lc;
 
        /* Collect row security information */
-       context->glob->hasRowSecurity = query->hasRowSecurity;
+       if (query->hasRowSecurity)
+           context->glob->hasRowSecurity = true;
 
        if (query->commandType == CMD_UTILITY)
        {
index d4b9c706465491fb33ff9bb628af7a09abb57c2d..2102eab4577105891176f60fbbe6490a6c1fa0bd 100644 (file)
@@ -1649,7 +1649,8 @@ ERROR:  new row violates row-level security policy for table "document"
 --
 SET SESSION AUTHORIZATION rls_regress_user0;
 CREATE TABLE z1 (a int, b text);
-GRANT SELECT ON z1 TO rls_regress_group1, rls_regress_group2,
+CREATE TABLE z2 (a int, b text);
+GRANT SELECT ON z1,z2 TO rls_regress_group1, rls_regress_group2,
     rls_regress_user1, rls_regress_user2;
 INSERT INTO z1 VALUES
     (1, 'aaa'),
@@ -1678,6 +1679,46 @@ EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b);
          Filter: ((a % 2) = 0)
 (4 rows)
 
+PREPARE plancache_test AS SELECT * FROM z1 WHERE f_leak(b);
+EXPLAIN EXECUTE plancache_test;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Subquery Scan on z1  (cost=0.00..29.11 rows=2 width=36)
+   Filter: f_leak(z1.b)
+   ->  Seq Scan on z1 z1_1  (cost=0.00..29.05 rows=6 width=36)
+         Filter: ((a % 2) = 0)
+(4 rows)
+
+PREPARE plancache_test2 AS WITH q AS (SELECT * FROM z1 WHERE f_leak(b)) SELECT * FROM q,z2;
+EXPLAIN EXECUTE plancache_test2;
+                              QUERY PLAN                               
+-----------------------------------------------------------------------
+ Nested Loop  (cost=29.11..86.78 rows=2540 width=72)
+   CTE q
+     ->  Subquery Scan on z1  (cost=0.00..29.11 rows=2 width=36)
+           Filter: f_leak(z1.b)
+           ->  Seq Scan on z1 z1_1  (cost=0.00..29.05 rows=6 width=36)
+                 Filter: ((a % 2) = 0)
+   ->  CTE Scan on q  (cost=0.00..0.04 rows=2 width=36)
+   ->  Materialize  (cost=0.00..29.05 rows=1270 width=36)
+         ->  Seq Scan on z2  (cost=0.00..22.70 rows=1270 width=36)
+(9 rows)
+
+PREPARE plancache_test3 AS WITH q AS (SELECT * FROM z2) SELECT * FROM q,z1 WHERE f_leak(z1.b);
+EXPLAIN EXECUTE plancache_test3;
+                                QUERY PLAN                                 
+---------------------------------------------------------------------------
+ Nested Loop  (cost=22.70..108.97 rows=2540 width=72)
+   CTE q
+     ->  Seq Scan on z2  (cost=0.00..22.70 rows=1270 width=36)
+   ->  CTE Scan on q  (cost=0.00..25.40 rows=1270 width=36)
+   ->  Materialize  (cost=0.00..29.12 rows=2 width=36)
+         ->  Subquery Scan on z1  (cost=0.00..29.11 rows=2 width=36)
+               Filter: f_leak(z1.b)
+               ->  Seq Scan on z1 z1_1  (cost=0.00..29.05 rows=6 width=36)
+                     Filter: ((a % 2) = 0)
+(9 rows)
+
 SET ROLE rls_regress_group1;
 SELECT * FROM z1 WHERE f_leak(b);
 NOTICE:  f_leak => bbb
@@ -1697,6 +1738,43 @@ EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b);
          Filter: ((a % 2) = 0)
 (4 rows)
 
+EXPLAIN EXECUTE plancache_test;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Subquery Scan on z1  (cost=0.00..29.11 rows=2 width=36)
+   Filter: f_leak(z1.b)
+   ->  Seq Scan on z1 z1_1  (cost=0.00..29.05 rows=6 width=36)
+         Filter: ((a % 2) = 0)
+(4 rows)
+
+EXPLAIN EXECUTE plancache_test2;
+                              QUERY PLAN                               
+-----------------------------------------------------------------------
+ Nested Loop  (cost=29.11..86.78 rows=2540 width=72)
+   CTE q
+     ->  Subquery Scan on z1  (cost=0.00..29.11 rows=2 width=36)
+           Filter: f_leak(z1.b)
+           ->  Seq Scan on z1 z1_1  (cost=0.00..29.05 rows=6 width=36)
+                 Filter: ((a % 2) = 0)
+   ->  CTE Scan on q  (cost=0.00..0.04 rows=2 width=36)
+   ->  Materialize  (cost=0.00..29.05 rows=1270 width=36)
+         ->  Seq Scan on z2  (cost=0.00..22.70 rows=1270 width=36)
+(9 rows)
+
+EXPLAIN EXECUTE plancache_test3;
+                                QUERY PLAN                                 
+---------------------------------------------------------------------------
+ Nested Loop  (cost=22.70..108.97 rows=2540 width=72)
+   CTE q
+     ->  Seq Scan on z2  (cost=0.00..22.70 rows=1270 width=36)
+   ->  CTE Scan on q  (cost=0.00..25.40 rows=1270 width=36)
+   ->  Materialize  (cost=0.00..29.12 rows=2 width=36)
+         ->  Subquery Scan on z1  (cost=0.00..29.11 rows=2 width=36)
+               Filter: f_leak(z1.b)
+               ->  Seq Scan on z1 z1_1  (cost=0.00..29.05 rows=6 width=36)
+                     Filter: ((a % 2) = 0)
+(9 rows)
+
 SET SESSION AUTHORIZATION rls_regress_user2;
 SELECT * FROM z1 WHERE f_leak(b);
 NOTICE:  f_leak => aaa
@@ -1716,6 +1794,43 @@ EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b);
          Filter: ((a % 2) = 1)
 (4 rows)
 
+EXPLAIN EXECUTE plancache_test;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Subquery Scan on z1  (cost=0.00..29.11 rows=2 width=36)
+   Filter: f_leak(z1.b)
+   ->  Seq Scan on z1 z1_1  (cost=0.00..29.05 rows=6 width=36)
+         Filter: ((a % 2) = 1)
+(4 rows)
+
+EXPLAIN EXECUTE plancache_test2;
+                              QUERY PLAN                               
+-----------------------------------------------------------------------
+ Nested Loop  (cost=29.11..86.78 rows=2540 width=72)
+   CTE q
+     ->  Subquery Scan on z1  (cost=0.00..29.11 rows=2 width=36)
+           Filter: f_leak(z1.b)
+           ->  Seq Scan on z1 z1_1  (cost=0.00..29.05 rows=6 width=36)
+                 Filter: ((a % 2) = 1)
+   ->  CTE Scan on q  (cost=0.00..0.04 rows=2 width=36)
+   ->  Materialize  (cost=0.00..29.05 rows=1270 width=36)
+         ->  Seq Scan on z2  (cost=0.00..22.70 rows=1270 width=36)
+(9 rows)
+
+EXPLAIN EXECUTE plancache_test3;
+                                QUERY PLAN                                 
+---------------------------------------------------------------------------
+ Nested Loop  (cost=22.70..108.97 rows=2540 width=72)
+   CTE q
+     ->  Seq Scan on z2  (cost=0.00..22.70 rows=1270 width=36)
+   ->  CTE Scan on q  (cost=0.00..25.40 rows=1270 width=36)
+   ->  Materialize  (cost=0.00..29.12 rows=2 width=36)
+         ->  Subquery Scan on z1  (cost=0.00..29.11 rows=2 width=36)
+               Filter: f_leak(z1.b)
+               ->  Seq Scan on z1 z1_1  (cost=0.00..29.05 rows=6 width=36)
+                     Filter: ((a % 2) = 1)
+(9 rows)
+
 SET ROLE rls_regress_group2;
 SELECT * FROM z1 WHERE f_leak(b);
 NOTICE:  f_leak => aaa
@@ -1735,6 +1850,43 @@ EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b);
          Filter: ((a % 2) = 1)
 (4 rows)
 
+EXPLAIN EXECUTE plancache_test;
+                          QUERY PLAN                           
+---------------------------------------------------------------
+ Subquery Scan on z1  (cost=0.00..29.11 rows=2 width=36)
+   Filter: f_leak(z1.b)
+   ->  Seq Scan on z1 z1_1  (cost=0.00..29.05 rows=6 width=36)
+         Filter: ((a % 2) = 1)
+(4 rows)
+
+EXPLAIN EXECUTE plancache_test2;
+                              QUERY PLAN                               
+-----------------------------------------------------------------------
+ Nested Loop  (cost=29.11..86.78 rows=2540 width=72)
+   CTE q
+     ->  Subquery Scan on z1  (cost=0.00..29.11 rows=2 width=36)
+           Filter: f_leak(z1.b)
+           ->  Seq Scan on z1 z1_1  (cost=0.00..29.05 rows=6 width=36)
+                 Filter: ((a % 2) = 1)
+   ->  CTE Scan on q  (cost=0.00..0.04 rows=2 width=36)
+   ->  Materialize  (cost=0.00..29.05 rows=1270 width=36)
+         ->  Seq Scan on z2  (cost=0.00..22.70 rows=1270 width=36)
+(9 rows)
+
+EXPLAIN EXECUTE plancache_test3;
+                                QUERY PLAN                                 
+---------------------------------------------------------------------------
+ Nested Loop  (cost=22.70..108.97 rows=2540 width=72)
+   CTE q
+     ->  Seq Scan on z2  (cost=0.00..22.70 rows=1270 width=36)
+   ->  CTE Scan on q  (cost=0.00..25.40 rows=1270 width=36)
+   ->  Materialize  (cost=0.00..29.12 rows=2 width=36)
+         ->  Subquery Scan on z1  (cost=0.00..29.11 rows=2 width=36)
+               Filter: f_leak(z1.b)
+               ->  Seq Scan on z1 z1_1  (cost=0.00..29.05 rows=6 width=36)
+                     Filter: ((a % 2) = 1)
+(9 rows)
+
 --
 -- Views should follow policy for view owner.
 --
index 3966a55f2ca0d67b8f11d048d59c69a28c2a35a8..34c551da8239932db9e793fcfb319e16c6334ab0 100644 (file)
@@ -629,8 +629,9 @@ INSERT INTO document VALUES (1, (SELECT cid from category WHERE cname = 'novel')
 --
 SET SESSION AUTHORIZATION rls_regress_user0;
 CREATE TABLE z1 (a int, b text);
+CREATE TABLE z2 (a int, b text);
 
-GRANT SELECT ON z1 TO rls_regress_group1, rls_regress_group2,
+GRANT SELECT ON z1,z2 TO rls_regress_group1, rls_regress_group2,
     rls_regress_user1, rls_regress_user2;
 
 INSERT INTO z1 VALUES
@@ -648,18 +649,39 @@ SET SESSION AUTHORIZATION rls_regress_user1;
 SELECT * FROM z1 WHERE f_leak(b);
 EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b);
 
+PREPARE plancache_test AS SELECT * FROM z1 WHERE f_leak(b);
+EXPLAIN EXECUTE plancache_test;
+
+PREPARE plancache_test2 AS WITH q AS (SELECT * FROM z1 WHERE f_leak(b)) SELECT * FROM q,z2;
+EXPLAIN EXECUTE plancache_test2;
+
+PREPARE plancache_test3 AS WITH q AS (SELECT * FROM z2) SELECT * FROM q,z1 WHERE f_leak(z1.b);
+EXPLAIN EXECUTE plancache_test3;
+
 SET ROLE rls_regress_group1;
 SELECT * FROM z1 WHERE f_leak(b);
 EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b);
 
+EXPLAIN EXECUTE plancache_test;
+EXPLAIN EXECUTE plancache_test2;
+EXPLAIN EXECUTE plancache_test3;
+
 SET SESSION AUTHORIZATION rls_regress_user2;
 SELECT * FROM z1 WHERE f_leak(b);
 EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b);
 
+EXPLAIN EXECUTE plancache_test;
+EXPLAIN EXECUTE plancache_test2;
+EXPLAIN EXECUTE plancache_test3;
+
 SET ROLE rls_regress_group2;
 SELECT * FROM z1 WHERE f_leak(b);
 EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b);
 
+EXPLAIN EXECUTE plancache_test;
+EXPLAIN EXECUTE plancache_test2;
+EXPLAIN EXECUTE plancache_test3;
+
 --
 -- Views should follow policy for view owner.
 --