diff options
Diffstat (limited to 'src/test')
-rw-r--r-- | src/test/modules/test_rls_hooks/expected/test_rls_hooks.out | 24 | ||||
-rw-r--r-- | src/test/regress/expected/equivclass.out | 42 | ||||
-rw-r--r-- | src/test/regress/expected/rowsecurity.out | 877 | ||||
-rw-r--r-- | src/test/regress/expected/updatable_views.out | 304 | ||||
-rw-r--r-- | src/test/regress/sql/equivclass.sql | 32 | ||||
-rw-r--r-- | src/test/regress/sql/updatable_views.sql | 4 |
6 files changed, 543 insertions, 740 deletions
diff --git a/src/test/modules/test_rls_hooks/expected/test_rls_hooks.out b/src/test/modules/test_rls_hooks/expected/test_rls_hooks.out index 19284c18d48..b8c6d385814 100644 --- a/src/test/modules/test_rls_hooks/expected/test_rls_hooks.out +++ b/src/test/modules/test_rls_hooks/expected/test_rls_hooks.out @@ -145,13 +145,11 @@ ERROR: new row violates row-level security policy for table "rls_test_permissiv SET ROLE regress_s1; -- With both internal and hook policies, restrictive EXPLAIN (costs off) SELECT * FROM rls_test_restrictive; - QUERY PLAN ---------------------------------------------------------------- - Subquery Scan on rls_test_restrictive - Filter: ((rls_test_restrictive.data % 2) = 0) - -> Seq Scan on rls_test_restrictive rls_test_restrictive_1 - Filter: ("current_user"() = supervisor) -(4 rows) + QUERY PLAN +------------------------------------------------------------------ + Seq Scan on rls_test_restrictive + Filter: (("current_user"() = supervisor) AND ((data % 2) = 0)) +(2 rows) SELECT * FROM rls_test_restrictive; username | supervisor | data @@ -173,13 +171,11 @@ ERROR: new row violates row-level security policy for table "rls_test_restricti -- With both internal and hook policies, both permissive -- and restrictive hook policies EXPLAIN (costs off) SELECT * FROM rls_test_both; - QUERY PLAN -------------------------------------------------------------------------------------------- - Subquery Scan on rls_test_both - Filter: (((rls_test_both.data % 2) = 0) OR ("current_user"() = rls_test_both.username)) - -> Seq Scan on rls_test_both rls_test_both_1 - Filter: ("current_user"() = supervisor) -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------------------------------- + Seq Scan on rls_test_both + Filter: (("current_user"() = supervisor) AND (((data % 2) = 0) OR ("current_user"() = username))) +(2 rows) SELECT * FROM rls_test_both; username | supervisor | data diff --git a/src/test/regress/expected/equivclass.out b/src/test/regress/expected/equivclass.out index 0391b8eec19..564218b767a 100644 --- a/src/test/regress/expected/equivclass.out +++ b/src/test/regress/expected/equivclass.out @@ -381,3 +381,45 @@ explain (costs off) Index Cond: (ff = '42'::bigint) (14 rows) +-- check effects of row-level security +set enable_nestloop = on; +set enable_mergejoin = off; +alter table ec1 enable row level security; +create policy p1 on ec1 using (f1 < '5'::int8alias1); +create user regress_user_ectest; +grant select on ec0 to regress_user_ectest; +grant select on ec1 to regress_user_ectest; +-- without any RLS, we'll treat {a.ff, b.ff, 43} as an EquivalenceClass +explain (costs off) + select * from ec0 a, ec1 b + where a.ff = b.ff and a.ff = 43::bigint::int8alias1; + QUERY PLAN +--------------------------------------------- + Nested Loop + -> Index Scan using ec0_pkey on ec0 a + Index Cond: (ff = '43'::int8alias1) + -> Index Scan using ec1_pkey on ec1 b + Index Cond: (ff = '43'::int8alias1) +(5 rows) + +set session authorization regress_user_ectest; +-- with RLS active, the non-leakproof a.ff = 43 clause is not treated +-- as a suitable source for an EquivalenceClass; currently, this is true +-- even though the RLS clause has nothing to do directly with the EC +explain (costs off) + select * from ec0 a, ec1 b + where a.ff = b.ff and a.ff = 43::bigint::int8alias1; + QUERY PLAN +--------------------------------------------- + Nested Loop + -> Index Scan using ec0_pkey on ec0 a + Index Cond: (ff = '43'::int8alias1) + -> Index Scan using ec1_pkey on ec1 b + Index Cond: (ff = a.ff) + Filter: (f1 < '5'::int8alias1) +(6 rows) + +reset session authorization; +revoke select on ec0 from regress_user_ectest; +revoke select on ec1 from regress_user_ectest; +drop user regress_user_ectest; diff --git a/src/test/regress/expected/rowsecurity.out b/src/test/regress/expected/rowsecurity.out index 471e405c7ab..25407bf9ddd 100644 --- a/src/test/regress/expected/rowsecurity.out +++ b/src/test/regress/expected/rowsecurity.out @@ -265,32 +265,28 @@ NOTICE: f_leak => awesome science fiction (5 rows) EXPLAIN (COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle); - QUERY PLAN ----------------------------------------------------------- - Subquery Scan on document - Filter: f_leak(document.dtitle) - -> Seq Scan on document document_1 - Filter: (dlevel <= $0) - InitPlan 1 (returns $0) - -> Index Scan using uaccount_pkey on uaccount - Index Cond: (pguser = CURRENT_USER) -(7 rows) + QUERY PLAN +---------------------------------------------------- + Seq Scan on document + Filter: ((dlevel <= $0) AND f_leak(dtitle)) + InitPlan 1 (returns $0) + -> Index Scan using uaccount_pkey on uaccount + Index Cond: (pguser = CURRENT_USER) +(5 rows) EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle); - QUERY PLAN ----------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------- Hash Join Hash Cond: (category.cid = document.cid) + InitPlan 1 (returns $0) + -> Index Scan using uaccount_pkey on uaccount + Index Cond: (pguser = CURRENT_USER) -> Seq Scan on category -> Hash - -> Subquery Scan on document - Filter: f_leak(document.dtitle) - -> Seq Scan on document document_1 - Filter: (dlevel <= $0) - InitPlan 1 (returns $0) - -> Index Scan using uaccount_pkey on uaccount - Index Cond: (pguser = CURRENT_USER) -(11 rows) + -> Seq Scan on document + Filter: ((dlevel <= $0) AND f_leak(dtitle)) +(9 rows) -- viewpoint from regress_rls_dave SET SESSION AUTHORIZATION regress_rls_dave; @@ -333,32 +329,28 @@ NOTICE: f_leak => awesome technology book (7 rows) EXPLAIN (COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle); - QUERY PLAN ---------------------------------------------------------------------------------- - Subquery Scan on document - Filter: f_leak(document.dtitle) - -> Seq Scan on document document_1 - Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0)) - InitPlan 1 (returns $0) - -> Index Scan using uaccount_pkey on uaccount - Index Cond: (pguser = CURRENT_USER) -(7 rows) + QUERY PLAN +---------------------------------------------------------------------------------------------- + Seq Scan on document + Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle)) + InitPlan 1 (returns $0) + -> Index Scan using uaccount_pkey on uaccount + Index Cond: (pguser = CURRENT_USER) +(5 rows) EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle); - QUERY PLAN ---------------------------------------------------------------------------------------------- + QUERY PLAN +---------------------------------------------------------------------------------------------------------- Hash Join Hash Cond: (category.cid = document.cid) + InitPlan 1 (returns $0) + -> Index Scan using uaccount_pkey on uaccount + Index Cond: (pguser = CURRENT_USER) -> Seq Scan on category -> Hash - -> Subquery Scan on document - Filter: f_leak(document.dtitle) - -> Seq Scan on document document_1 - Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0)) - InitPlan 1 (returns $0) - -> Index Scan using uaccount_pkey on uaccount - Index Cond: (pguser = CURRENT_USER) -(11 rows) + -> Seq Scan on document + Filter: ((cid <> 44) AND (cid <> 44) AND (cid < 50) AND (dlevel <= $0) AND f_leak(dtitle)) +(9 rows) -- 44 would technically fail for both p2r and p1r, but we should get an error -- back from p1r for this because it sorts first @@ -431,25 +423,21 @@ NOTICE: f_leak => great manga (3 rows) EXPLAIN (COSTS OFF) SELECT * FROM document WHERE f_leak(dtitle); - QUERY PLAN ------------------------------------------- - Subquery Scan on document - Filter: f_leak(document.dtitle) - -> Seq Scan on document document_1 - Filter: (dauthor = CURRENT_USER) -(4 rows) + QUERY PLAN +--------------------------------------------------------- + Seq Scan on document + Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle)) +(2 rows) EXPLAIN (COSTS OFF) SELECT * FROM document NATURAL JOIN category WHERE f_leak(dtitle); - QUERY PLAN --------------------------------------------------- + QUERY PLAN +--------------------------------------------------------------- Nested Loop - -> Subquery Scan on document - Filter: f_leak(document.dtitle) - -> Seq Scan on document document_1 - Filter: (dauthor = CURRENT_USER) + -> Seq Scan on document + Filter: ((dauthor = CURRENT_USER) AND f_leak(dtitle)) -> Index Scan using category_pkey on category Index Cond: (cid = document.cid) -(7 rows) +(5 rows) -- interaction of FK/PK constraints SET SESSION AUTHORIZATION regress_rls_alice; @@ -698,18 +686,16 @@ NOTICE: f_leak => yyy (5 rows) EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b); - QUERY PLAN -------------------------------------- - Subquery Scan on t1 - Filter: f_leak(t1.b) - -> Append - -> Seq Scan on t1 t1_1 - Filter: ((a % 2) = 0) - -> Seq Scan on t2 - Filter: ((a % 2) = 0) - -> Seq Scan on t3 - Filter: ((a % 2) = 0) -(9 rows) + QUERY PLAN +----------------------------------------------- + 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)) +(7 rows) -- reference to system column SELECT oid, * FROM t1; @@ -769,20 +755,17 @@ SELECT * FROM t1 FOR SHARE; (5 rows) EXPLAIN (COSTS OFF) SELECT * FROM t1 FOR SHARE; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +------------------------------------- LockRows - -> Subquery Scan on t1 - -> LockRows - -> Result - -> Append - -> Seq Scan on t1 t1_1 - Filter: ((a % 2) = 0) - -> Seq Scan on t2 - Filter: ((a % 2) = 0) - -> Seq Scan on t3 - Filter: ((a % 2) = 0) -(11 rows) + -> 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) +(8 rows) SELECT * FROM t1 WHERE f_leak(b) FOR SHARE; NOTICE: f_leak => bbb @@ -800,21 +783,17 @@ NOTICE: f_leak => yyy (5 rows) EXPLAIN (COSTS OFF) SELECT * FROM t1 WHERE f_leak(b) FOR SHARE; - QUERY PLAN -------------------------------------------------------- + QUERY PLAN +----------------------------------------------------- LockRows - -> Subquery Scan on t1 - Filter: f_leak(t1.b) - -> LockRows - -> Result - -> Append - -> Seq Scan on t1 t1_1 - Filter: ((a % 2) = 0) - -> Seq Scan on t2 - Filter: ((a % 2) = 0) - -> Seq Scan on t3 - Filter: ((a % 2) = 0) -(12 rows) + -> 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)) +(8 rows) -- union all query SELECT a, b, oid FROM t2 UNION ALL SELECT a, b, oid FROM t3; @@ -1024,21 +1003,14 @@ NOTICE: f_leak => a87ff679a2f3e71d9181a67b7542122c (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM only s1 WHERE f_leak(b); - QUERY PLAN ----------------------------------------------------------- - Subquery Scan on s1 - Filter: f_leak(s1.b) - -> Hash Join - Hash Cond: (s1_1.a = s2.x) - -> Seq Scan on s1 s1_1 - -> Hash - -> HashAggregate - Group Key: s2.x - -> Subquery Scan on s2 - Filter: (s2.y ~~ '%2f%'::text) - -> Seq Scan on s2 s2_1 - Filter: ((x % 2) = 0) -(12 rows) + QUERY PLAN +----------------------------------------------------------- + Seq Scan on s1 + Filter: ((hashed SubPlan 1) AND f_leak(b)) + SubPlan 1 + -> Seq Scan on s2 + Filter: (((x % 2) = 0) AND (y ~~ '%2f%'::text)) +(5 rows) SET SESSION AUTHORIZATION regress_rls_alice; ALTER POLICY p1 ON s1 USING (a in (select x from v2)); -- using VIEW in RLS policy @@ -1053,21 +1025,14 @@ NOTICE: f_leak => 1679091c5a880faf6fb5e6087eb1b2dc (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM s1 WHERE f_leak(b); - QUERY PLAN ----------------------------------------------------------- - Subquery Scan on s1 - Filter: f_leak(s1.b) - -> Hash Join - Hash Cond: (s1_1.a = s2.x) - -> Seq Scan on s1 s1_1 - -> Hash - -> HashAggregate - Group Key: s2.x - -> Subquery Scan on s2 - Filter: (s2.y ~~ '%af%'::text) - -> Seq Scan on s2 s2_1 - Filter: ((x % 2) = 0) -(12 rows) + QUERY PLAN +----------------------------------------------------------- + Seq Scan on s1 + Filter: ((hashed SubPlan 1) AND f_leak(b)) + SubPlan 1 + -> Seq Scan on s2 + Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text)) +(5 rows) SELECT (SELECT x FROM s1 LIMIT 1) xx, * FROM s2 WHERE y like '%28%'; xx | x | y @@ -1078,24 +1043,18 @@ SELECT (SELECT x FROM s1 LIMIT 1) xx, * FROM s2 WHERE y like '%28%'; (3 rows) EXPLAIN (COSTS OFF) SELECT (SELECT x FROM s1 LIMIT 1) xx, * FROM s2 WHERE y like '%28%'; - QUERY PLAN --------------------------------------------------------------------- - Subquery Scan on s2 - Filter: (s2.y ~~ '%28%'::text) - -> Seq Scan on s2 s2_1 - Filter: ((x % 2) = 0) - SubPlan 1 + QUERY PLAN +------------------------------------------------------------------------- + Seq Scan on s2 + Filter: (((x % 2) = 0) AND (y ~~ '%28%'::text)) + SubPlan 2 -> Limit - -> Subquery Scan on s1 - -> Nested Loop Semi Join - Join Filter: (s1_1.a = s2_2.x) - -> Seq Scan on s1 s1_1 - -> Materialize - -> Subquery Scan on s2_2 - Filter: (s2_2.y ~~ '%af%'::text) - -> Seq Scan on s2 s2_3 - Filter: ((x % 2) = 0) -(15 rows) + -> Seq Scan on s1 + Filter: (hashed SubPlan 1) + SubPlan 1 + -> Seq Scan on s2 s2_1 + Filter: (((x % 2) = 0) AND (y ~~ '%af%'::text)) +(9 rows) SET SESSION AUTHORIZATION regress_rls_alice; ALTER POLICY p2 ON s2 USING (x in (select a from s1 where b like '%d2%')); @@ -1239,28 +1198,19 @@ EXPLAIN (COSTS OFF) EXECUTE p2(2); -- SET SESSION AUTHORIZATION regress_rls_bob; EXPLAIN (COSTS OFF) UPDATE t1 SET b = b || b WHERE f_leak(b); - QUERY PLAN -------------------------------------------- - 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) -(19 rows) + QUERY PLAN +----------------------------------------------- + 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)) +(10 rows) UPDATE t1 SET b = b || b WHERE f_leak(b); NOTICE: f_leak => bbb @@ -1269,15 +1219,12 @@ NOTICE: f_leak => bcd NOTICE: f_leak => def NOTICE: f_leak => yyy EXPLAIN (COSTS OFF) UPDATE only t1 SET b = b || '_updt' WHERE f_leak(b); - QUERY PLAN -------------------------------------------- - 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) -(6 rows) + QUERY PLAN +----------------------------------------------- + Update on t1 + -> Seq Scan on t1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(3 rows) UPDATE only t1 SET b = b || '_updt' WHERE f_leak(b); NOTICE: f_leak => bbbbbb @@ -1325,89 +1272,63 @@ NOTICE: f_leak => yyyyyy -- updates with from clause EXPLAIN (COSTS OFF) UPDATE t2 SET b=t2.b FROM t3 WHERE t2.a = 3 and t3.a = 2 AND f_leak(t2.b) AND f_leak(t3.b); - QUERY PLAN ---------------------------------------------------------------- - Update on t2 t2_1 + QUERY PLAN +----------------------------------------------------------------- + Update on t2 -> Nested Loop - -> Subquery Scan on t2 - Filter: f_leak(t2.b) - -> LockRows - -> Seq Scan on t2 t2_2 - Filter: ((a = 3) AND ((a % 2) = 1)) + -> Seq Scan on t2 + Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) -> Seq Scan on t3 - Filter: (f_leak(b) AND (a = 2)) -(9 rows) + Filter: ((a = 2) AND f_leak(b)) +(6 rows) UPDATE t2 SET b=t2.b FROM t3 WHERE t2.a = 3 and t3.a = 2 AND f_leak(t2.b) AND f_leak(t3.b); NOTICE: f_leak => cde -NOTICE: f_leak => xxx -NOTICE: f_leak => zzz NOTICE: f_leak => yyyyyy EXPLAIN (COSTS OFF) UPDATE t1 SET b=t1.b FROM t2 WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b); - QUERY PLAN ---------------------------------------------------------------- - Update on t1 t1_3 - Update on t1 t1_3 - Update on t2 t1 - Update on t3 t1 + QUERY PLAN +----------------------------------------------------------------- + Update on t1 + Update on t1 + Update on t2 t2_1 + Update on t3 -> Nested Loop - -> Subquery Scan on t1 - Filter: f_leak(t1.b) - -> LockRows - -> Seq Scan on t1 t1_4 - Filter: ((a = 3) AND ((a % 2) = 0)) - -> Subquery Scan on t2 - Filter: f_leak(t2.b) - -> Seq Scan on t2 t2_3 - Filter: ((a = 3) AND ((a % 2) = 1)) + -> Seq Scan on t1 + Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 + Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) -> Nested Loop - -> Subquery Scan on t1_1 - Filter: f_leak(t1_1.b) - -> LockRows - -> Seq Scan on t2 t2_4 - Filter: ((a = 3) AND ((a % 2) = 0)) - -> Subquery Scan on t2_1 - Filter: f_leak(t2_1.b) - -> Seq Scan on t2 t2_5 - Filter: ((a = 3) AND ((a % 2) = 1)) + -> Seq Scan on t2 t2_1 + Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 + Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) -> Nested Loop - -> Subquery Scan on t1_2 - Filter: f_leak(t1_2.b) - -> LockRows - -> Seq Scan on t3 - Filter: ((a = 3) AND ((a % 2) = 0)) - -> Subquery Scan on t2_2 - Filter: f_leak(t2_2.b) - -> Seq Scan on t2 t2_6 - Filter: ((a = 3) AND ((a % 2) = 1)) -(34 rows) + -> Seq Scan on t3 + Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 + Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) +(19 rows) UPDATE t1 SET b=t1.b FROM t2 WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b); EXPLAIN (COSTS OFF) UPDATE t2 SET b=t2.b FROM t1 WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b); - QUERY PLAN ---------------------------------------------------------------------- - Update on t2 t2_1 + QUERY PLAN +----------------------------------------------------------------------- + Update on t2 -> Nested Loop - -> Subquery Scan on t2 - Filter: f_leak(t2.b) - -> LockRows - -> Seq Scan on t2 t2_2 - Filter: ((a = 3) AND ((a % 2) = 1)) - -> Subquery Scan on t1 - Filter: f_leak(t1.b) - -> Result - -> Append - -> Seq Scan on t1 t1_1 - Filter: ((a = 3) AND ((a % 2) = 0)) - -> Seq Scan on t2 t2_3 - Filter: ((a = 3) AND ((a % 2) = 0)) - -> Seq Scan on t3 - Filter: ((a = 3) AND ((a % 2) = 0)) -(17 rows) + -> Seq Scan on t2 + Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) + -> Append + -> Seq Scan on t1 + Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 t2_1 + Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t3 + Filter: ((a = 3) AND ((a % 2) = 0) AND f_leak(b)) +(11 rows) UPDATE t2 SET b=t2.b FROM t1 WHERE t1.a = 3 and t2.a = 3 AND f_leak(t1.b) AND f_leak(t2.b); @@ -1416,21 +1337,16 @@ NOTICE: f_leak => cde EXPLAIN (COSTS OFF) UPDATE t2 t2_1 SET b = t2_2.b FROM t2 t2_2 WHERE t2_1.a = 3 AND t2_2.a = t2_1.a AND t2_2.b = t2_1.b AND f_leak(t2_1.b) AND f_leak(t2_2.b) RETURNING *, t2_1, t2_2; - QUERY PLAN ---------------------------------------------------------------- - Update on t2 t2_1_1 + QUERY PLAN +----------------------------------------------------------------- + Update on t2 t2_1 -> Nested Loop Join Filter: (t2_1.b = t2_2.b) - -> Subquery Scan on t2_1 - Filter: f_leak(t2_1.b) - -> LockRows - -> Seq Scan on t2 t2_1_2 - Filter: ((a = 3) AND ((a % 2) = 1)) - -> Subquery Scan on t2_2 - Filter: f_leak(t2_2.b) - -> Seq Scan on t2 t2_2_1 - Filter: ((a = 3) AND ((a % 2) = 1)) -(12 rows) + -> Seq Scan on t2 t2_1 + Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) + -> Seq Scan on t2 t2_2 + Filter: ((a = 3) AND ((a % 2) = 1) AND f_leak(b)) +(7 rows) UPDATE t2 t2_1 SET b = t2_2.b FROM t2 t2_2 WHERE t2_1.a = 3 AND t2_2.a = t2_1.a AND t2_2.b = t2_1.b @@ -1445,61 +1361,46 @@ NOTICE: f_leak => cde EXPLAIN (COSTS OFF) UPDATE t1 t1_1 SET b = t1_2.b FROM t1 t1_2 WHERE t1_1.a = 4 AND t1_2.a = t1_1.a AND t1_2.b = t1_1.b AND f_leak(t1_1.b) AND f_leak(t1_2.b) RETURNING *, t1_1, t1_2; - QUERY PLAN ---------------------------------------------------------------- - Update on t1 t1_1_3 - Update on t1 t1_1_3 - Update on t2 t1_1 - Update on t3 t1_1 + QUERY PLAN +----------------------------------------------------------------------- + Update on t1 t1_1 + Update on t1 t1_1 + Update on t2 t1_1_1 + Update on t3 t1_1_2 -> Nested Loop Join Filter: (t1_1.b = t1_2.b) - -> Subquery Scan on t1_1 - Filter: f_leak(t1_1.b) - -> LockRows - -> Seq Scan on t1 t1_1_4 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Subquery Scan on t1_2 - Filter: f_leak(t1_2.b) - -> Append - -> Seq Scan on t1 t1_2_3 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Seq Scan on t2 t1_2_4 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Seq Scan on t3 t1_2_5 - Filter: ((a = 4) AND ((a % 2) = 0)) + -> Seq Scan on t1 t1_1 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Append + -> Seq Scan on t1 t1_2 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 t1_2_1 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t3 t1_2_2 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) -> Nested Loop - Join Filter: (t1_1_1.b = t1_2_1.b) - -> Subquery Scan on t1_1_1 - Filter: f_leak(t1_1_1.b) - -> LockRows - -> Seq Scan on t2 t1_1_5 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Subquery Scan on t1_2_1 - Filter: f_leak(t1_2_1.b) - -> Append - -> Seq Scan on t1 t1_2_6 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Seq Scan on t2 t1_2_7 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Seq Scan on t3 t1_2_8 - Filter: ((a = 4) AND ((a % 2) = 0)) + Join Filter: (t1_1_1.b = t1_2.b) + -> Seq Scan on t2 t1_1_1 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Append + -> Seq Scan on t1 t1_2 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 t1_2_1 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t3 t1_2_2 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) -> Nested Loop - Join Filter: (t1_1_2.b = t1_2_2.b) - -> Subquery Scan on t1_1_2 - Filter: f_leak(t1_1_2.b) - -> LockRows - -> Seq Scan on t3 t1_1_6 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Subquery Scan on t1_2_2 - Filter: f_leak(t1_2_2.b) - -> Append - -> Seq Scan on t1 t1_2_9 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Seq Scan on t2 t1_2_10 - Filter: ((a = 4) AND ((a % 2) = 0)) - -> Seq Scan on t3 t1_2_11 - Filter: ((a = 4) AND ((a % 2) = 0)) -(52 rows) + Join Filter: (t1_1_2.b = t1_2.b) + -> Seq Scan on t3 t1_1_2 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Append + -> Seq Scan on t1 t1_2 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t2 t1_2_1 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) + -> Seq Scan on t3 t1_2_2 + Filter: ((a = 4) AND ((a % 2) = 0) AND f_leak(b)) +(37 rows) UPDATE t1 t1_1 SET b = t1_2.b FROM t1 t1_2 WHERE t1_1.a = 4 AND t1_2.a = t1_1.a AND t1_2.b = t1_1.b @@ -1537,39 +1438,27 @@ SELECT * FROM t1 ORDER BY a,b; SET SESSION AUTHORIZATION regress_rls_bob; SET row_security TO ON; EXPLAIN (COSTS OFF) DELETE FROM only t1 WHERE f_leak(b); - QUERY PLAN -------------------------------------------- - 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) -(6 rows) + QUERY PLAN +----------------------------------------------- + Delete on t1 + -> Seq Scan on t1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(3 rows) EXPLAIN (COSTS OFF) DELETE FROM t1 WHERE f_leak(b); - QUERY PLAN -------------------------------------------- - 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) -(19 rows) + QUERY PLAN +----------------------------------------------- + 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)) +(10 rows) DELETE FROM only t1 WHERE f_leak(b) RETURNING oid, *, t1; NOTICE: f_leak => bbbbbb_updt @@ -1634,30 +1523,22 @@ 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 ---------------------------------------------------------------------------- - 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)) -(7 rows) + QUERY PLAN +----------------------------------------------------------------------- + Update on b1 + -> Seq Scan on b1 + Filter: ((a > 0) AND (a = 4) AND ((a % 2) = 0) AND f_leak(b)) +(3 rows) UPDATE bv1 SET b = 'yyy' WHERE a = 4 AND f_leak(b); NOTICE: f_leak => a87ff679a2f3e71d9181a67b7542122c EXPLAIN (COSTS OFF) DELETE FROM bv1 WHERE a = 6 AND f_leak(b); - QUERY PLAN ---------------------------------------------------------------------------- - 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)) -(7 rows) + QUERY PLAN +----------------------------------------------------------------------- + Delete on b1 + -> Seq Scan on b1 + Filter: ((a > 0) AND (a = 6) AND ((a % 2) = 0) AND f_leak(b)) +(3 rows) DELETE FROM bv1 WHERE a = 6 AND f_leak(b); NOTICE: f_leak => 1679091c5a880faf6fb5e6087eb1b2dc @@ -1848,53 +1729,45 @@ NOTICE: f_leak => dad (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b); - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(2 rows) PREPARE plancache_test AS SELECT * FROM z1 WHERE f_leak(b); EXPLAIN (COSTS OFF) EXECUTE plancache_test; - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(2 rows) PREPARE plancache_test2 AS WITH q AS (SELECT * FROM z1 WHERE f_leak(b)) SELECT * FROM q,z2; EXPLAIN (COSTS OFF) EXECUTE plancache_test2; - QUERY PLAN ---------------------------------------- + QUERY PLAN +------------------------------------------------- Nested Loop CTE q - -> Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) + -> Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) -> CTE Scan on q -> Materialize -> Seq Scan on z2 -(9 rows) +(7 rows) PREPARE plancache_test3 AS WITH q AS (SELECT * FROM z2) SELECT * FROM q,z1 WHERE f_leak(z1.b); EXPLAIN (COSTS OFF) EXECUTE plancache_test3; - QUERY PLAN -------------------------------------------- + QUERY PLAN +----------------------------------------------------- Nested Loop CTE q -> Seq Scan on z2 -> CTE Scan on q -> Materialize - -> Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(9 rows) + -> Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(7 rows) SET ROLE regress_rls_group1; SELECT * FROM z1 WHERE f_leak(b); @@ -1907,50 +1780,42 @@ NOTICE: f_leak => dad (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b); - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(2 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test; - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(2 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test2; - QUERY PLAN ---------------------------------------- + QUERY PLAN +------------------------------------------------- Nested Loop CTE q - -> Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) + -> Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) -> CTE Scan on q -> Materialize -> Seq Scan on z2 -(9 rows) +(7 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test3; - QUERY PLAN -------------------------------------------- + QUERY PLAN +----------------------------------------------------- Nested Loop CTE q -> Seq Scan on z2 -> CTE Scan on q -> Materialize - -> Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(9 rows) + -> Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(7 rows) SET SESSION AUTHORIZATION regress_rls_carol; SELECT * FROM z1 WHERE f_leak(b); @@ -1963,50 +1828,42 @@ NOTICE: f_leak => ccc (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b); - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 1) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 1) AND f_leak(b)) +(2 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test; - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 1) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 1) AND f_leak(b)) +(2 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test2; - QUERY PLAN ---------------------------------------- + QUERY PLAN +------------------------------------------------- Nested Loop CTE q - -> Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 1) + -> Seq Scan on z1 + Filter: (((a % 2) = 1) AND f_leak(b)) -> CTE Scan on q -> Materialize -> Seq Scan on z2 -(9 rows) +(7 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test3; - QUERY PLAN -------------------------------------------- + QUERY PLAN +----------------------------------------------------- Nested Loop CTE q -> Seq Scan on z2 -> CTE Scan on q -> Materialize - -> Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 1) -(9 rows) + -> Seq Scan on z1 + Filter: (((a % 2) = 1) AND f_leak(b)) +(7 rows) SET ROLE regress_rls_group2; SELECT * FROM z1 WHERE f_leak(b); @@ -2019,50 +1876,42 @@ NOTICE: f_leak => ccc (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM z1 WHERE f_leak(b); - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 1) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 1) AND f_leak(b)) +(2 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test; - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 1) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 1) AND f_leak(b)) +(2 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test2; - QUERY PLAN ---------------------------------------- + QUERY PLAN +------------------------------------------------- Nested Loop CTE q - -> Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 1) + -> Seq Scan on z1 + Filter: (((a % 2) = 1) AND f_leak(b)) -> CTE Scan on q -> Materialize -> Seq Scan on z2 -(9 rows) +(7 rows) EXPLAIN (COSTS OFF) EXECUTE plancache_test3; - QUERY PLAN -------------------------------------------- + QUERY PLAN +----------------------------------------------------- Nested Loop CTE q -> Seq Scan on z2 -> CTE Scan on q -> Materialize - -> Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 1) -(9 rows) + -> Seq Scan on z1 + Filter: (((a % 2) = 1) AND f_leak(b)) +(7 rows) -- -- Views should follow policy for view owner. @@ -2133,13 +1982,11 @@ NOTICE: f_leak => dad (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM rls_view; - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(2 rows) -- Query as role that is not owner of table but is owner of view. -- Should return records based on view owner policies. @@ -2154,13 +2001,11 @@ NOTICE: f_leak => dad (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM rls_view; - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(2 rows) -- Query as role that is not the owner of the table or view without permissions. SET SESSION AUTHORIZATION regress_rls_carol; @@ -2181,13 +2026,11 @@ NOTICE: f_leak => dad (2 rows) EXPLAIN (COSTS OFF) SELECT * FROM rls_view; - QUERY PLAN -------------------------------- - Subquery Scan on z1 - Filter: f_leak(z1.b) - -> Seq Scan on z1 z1_1 - Filter: ((a % 2) = 0) -(4 rows) + QUERY PLAN +----------------------------------------- + Seq Scan on z1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(2 rows) SET SESSION AUTHORIZATION regress_rls_bob; DROP VIEW rls_view; @@ -2333,13 +2176,11 @@ SET SESSION AUTHORIZATION regress_rls_bob; CREATE VIEW rls_sbv WITH (security_barrier) AS SELECT * FROM y1 WHERE f_leak(b); EXPLAIN (COSTS OFF) SELECT * FROM rls_sbv WHERE (a = 1); - QUERY PLAN ----------------------------------------------------------- - Subquery Scan on y1 - Filter: f_leak(y1.b) - -> Seq Scan on y1 y1_1 - Filter: ((a = 1) AND ((a > 2) OR ((a % 2) = 0))) -(4 rows) + QUERY PLAN +------------------------------------------------------------------ + Seq Scan on y1 + Filter: ((a = 1) AND ((a > 2) OR ((a % 2) = 0)) AND f_leak(b)) +(2 rows) DROP VIEW rls_sbv; -- @@ -2384,13 +2225,11 @@ NOTICE: f_leak => 98f13708210194c475687be6106a3b84 (14 rows) EXPLAIN (COSTS OFF) SELECT * FROM y2 WHERE f_leak(b); - QUERY PLAN -------------------------------------------------------------------- - Subquery Scan on y2 - Filter: f_leak(y2.b) - -> Seq Scan on y2 y2_1 - Filter: (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) -(4 rows) + QUERY PLAN +----------------------------------------------------------------------------- + Seq Scan on y2 + Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b)) +(2 rows) -- -- Qual push-down of leaky functions, when not referring to table @@ -2485,17 +2324,15 @@ NOTICE: f_leak => 98f13708210194c475687be6106a3b84 (0 rows) EXPLAIN (COSTS OFF) SELECT * FROM y2 JOIN test_qual_pushdown ON (b = abc) WHERE f_leak(b); - QUERY PLAN -------------------------------------------------------------------------------- + QUERY PLAN +----------------------------------------------------------------------------------------- Hash Join Hash Cond: (test_qual_pushdown.abc = y2.b) -> Seq Scan on test_qual_pushdown -> Hash - -> Subquery Scan on y2 - Filter: f_leak(y2.b) - -> Seq Scan on y2 y2_1 - Filter: (((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) -(8 rows) + -> Seq Scan on y2 + Filter: ((((a % 4) = 0) OR ((a % 3) = 0) OR ((a % 2) = 0)) AND f_leak(b)) +(6 rows) DROP TABLE test_qual_pushdown; -- @@ -2581,15 +2418,13 @@ NOTICE: f_leak => 98f13708210194c475687be6106a3b84 (11 rows) EXPLAIN (COSTS OFF) WITH cte1 AS (SELECT * FROM t1 WHERE f_leak(b)) SELECT * FROM cte1; - QUERY PLAN ---------------------------------------- + QUERY PLAN +------------------------------------------------- CTE Scan on cte1 CTE cte1 - -> Subquery Scan on t1 - Filter: f_leak(t1.b) - -> Seq Scan on t1 t1_1 - Filter: ((a % 2) = 0) -(6 rows) + -> Seq Scan on t1 + Filter: (((a % 2) = 0) AND f_leak(b)) +(4 rows) WITH cte1 AS (UPDATE t1 SET a = a + 1 RETURNING *) SELECT * FROM cte1; --fail ERROR: new row violates row-level security policy for table "t1" @@ -3100,17 +2935,13 @@ SELECT * FROM current_check; -- 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 current_check_1 - -> Subquery Scan on current_check - -> Subquery Scan on current_check_2 - Filter: ((current_check_2.currentid % 2) = 0) - -> LockRows - -> Tid Scan on current_check current_check_3 - TID Cond: CURRENT OF current_check_cursor - Filter: (currentid = 4) -(8 rows) + 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) -- Similarly can only delete row 4 FETCH ABSOLUTE 1 FROM current_check_cursor; diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out index 6fba613f0f5..2da3c069e11 100644 --- a/src/test/regress/expected/updatable_views.out +++ b/src/test/regress/expected/updatable_views.out @@ -1896,26 +1896,20 @@ EXPLAIN (costs off) SELECT * FROM rw_view1 WHERE snoop(person); (4 rows) EXPLAIN (costs off) UPDATE rw_view1 SET person=person WHERE snoop(person); - QUERY PLAN ------------------------------------------------------------ - Update on base_tbl base_tbl_1 - -> Subquery Scan on base_tbl - Filter: snoop(base_tbl.person) - -> LockRows - -> Seq Scan on base_tbl base_tbl_2 - Filter: (visibility = 'public'::text) -(6 rows) + QUERY PLAN +------------------------------------------------------------------- + Update on base_tbl + -> Seq Scan on base_tbl + Filter: ((visibility = 'public'::text) AND snoop(person)) +(3 rows) EXPLAIN (costs off) DELETE FROM rw_view1 WHERE NOT snoop(person); - QUERY PLAN ------------------------------------------------------------ - Delete on base_tbl base_tbl_1 - -> Subquery Scan on base_tbl - Filter: (NOT snoop(base_tbl.person)) - -> LockRows - -> Seq Scan on base_tbl base_tbl_2 - Filter: (visibility = 'public'::text) -(6 rows) + QUERY PLAN +------------------------------------------------------------------------- + Delete on base_tbl + -> Seq Scan on base_tbl + Filter: ((visibility = 'public'::text) AND (NOT snoop(person))) +(3 rows) -- security barrier view on top of security barrier view CREATE VIEW rw_view2 WITH (security_barrier = true) AS @@ -1978,30 +1972,20 @@ EXPLAIN (costs off) SELECT * FROM rw_view2 WHERE snoop(person); (6 rows) EXPLAIN (costs off) UPDATE rw_view2 SET person=person WHERE snoop(person); - QUERY PLAN ------------------------------------------------------------------ - Update on base_tbl base_tbl_1 - -> Subquery Scan on base_tbl - Filter: snoop(base_tbl.person) - -> Subquery Scan on base_tbl_2 - Filter: snoop(base_tbl_2.person) - -> LockRows - -> Seq Scan on base_tbl base_tbl_3 - Filter: (visibility = 'public'::text) -(8 rows) + QUERY PLAN +------------------------------------------------------------------------------------- + Update on base_tbl + -> Seq Scan on base_tbl + Filter: ((visibility = 'public'::text) AND snoop(person) AND snoop(person)) +(3 rows) EXPLAIN (costs off) DELETE FROM rw_view2 WHERE NOT snoop(person); - QUERY PLAN ------------------------------------------------------------------ - Delete on base_tbl base_tbl_1 - -> Subquery Scan on base_tbl - Filter: (NOT snoop(base_tbl.person)) - -> Subquery Scan on base_tbl_2 - Filter: snoop(base_tbl_2.person) - -> LockRows - -> Seq Scan on base_tbl base_tbl_3 - Filter: (visibility = 'public'::text) -(8 rows) + QUERY PLAN +------------------------------------------------------------------------------------------- + Delete on base_tbl + -> Seq Scan on base_tbl + Filter: ((visibility = 'public'::text) AND snoop(person) AND (NOT snoop(person))) +(3 rows) DROP TABLE base_tbl CASCADE; NOTICE: drop cascades to 2 other objects @@ -2026,18 +2010,16 @@ SELECT * FROM rw_view1; (1 row) EXPLAIN (costs off) DELETE FROM rw_view1 WHERE id = 1 AND snoop(data); - QUERY PLAN -------------------------------------------------------------------------- + QUERY PLAN +------------------------------------------------------------------- Update on base_tbl base_tbl_1 -> Nested Loop -> Index Scan using base_tbl_pkey on base_tbl base_tbl_1 Index Cond: (id = 1) - -> Subquery Scan on base_tbl - Filter: snoop(base_tbl.data) - -> Index Scan using base_tbl_pkey on base_tbl base_tbl_2 - Index Cond: (id = 1) - Filter: (NOT deleted) -(9 rows) + -> Index Scan using base_tbl_pkey on base_tbl + Index Cond: (id = 1) + Filter: ((NOT deleted) AND snoop(data)) +(7 rows) DELETE FROM rw_view1 WHERE id = 1 AND snoop(data); NOTICE: snooped value: Row 1 @@ -2114,85 +2096,45 @@ SELECT * FROM v1 WHERE a=8; (4 rows) EXPLAIN (VERBOSE, COSTS OFF) -UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a = 3; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Update on public.t1 t1_4 - Update on public.t1 t1_4 - Update on public.t11 t1 - Update on public.t12 t1 - Update on public.t111 t1 - -> Subquery Scan on t1 +UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a < 7 AND a != 6; + QUERY PLAN +--------------------------------------------------------------------------------------------------------------------------- + Update on public.t1 + Update on public.t1 + Update on public.t11 + Update on public.t12 + Update on public.t111 + -> Index Scan using t1_a_idx on public.t1 Output: 100, t1.b, t1.c, t1.ctid - Filter: snoop(t1.a) - -> LockRows - Output: t1_5.ctid, t1_5.a, t1_5.b, t1_5.c, t1_5.ctid, t12.ctid, t12.tableoid - -> Nested Loop Semi Join - Output: t1_5.ctid, t1_5.a, t1_5.b, t1_5.c, t1_5.ctid, t12.ctid, t12.tableoid - -> Seq Scan on public.t1 t1_5 - Output: t1_5.ctid, t1_5.a, t1_5.b, t1_5.c - Filter: ((t1_5.a > 5) AND (t1_5.a = 3) AND leakproof(t1_5.a)) - -> Append - -> Seq Scan on public.t12 - Output: t12.ctid, t12.tableoid, t12.a - Filter: (t12.a = 3) - -> Seq Scan on public.t111 - Output: t111.ctid, t111.tableoid, t111.a - Filter: (t111.a = 3) - -> Subquery Scan on t1_1 - Output: 100, t1_1.b, t1_1.c, t1_1.d, t1_1.ctid - Filter: snoop(t1_1.a) - -> LockRows - Output: t11.ctid, t11.a, t11.b, t11.c, t11.d, t11.ctid, t12_1.ctid, t12_1.tableoid - -> Nested Loop Semi Join - Output: t11.ctid, t11.a, t11.b, t11.c, t11.d, t11.ctid, t12_1.ctid, t12_1.tableoid - -> Seq Scan on public.t11 - Output: t11.ctid, t11.a, t11.b, t11.c, t11.d - Filter: ((t11.a > 5) AND (t11.a = 3) AND leakproof(t11.a)) - -> Append - -> Seq Scan on public.t12 t12_1 - Output: t12_1.ctid, t12_1.tableoid, t12_1.a - Filter: (t12_1.a = 3) - -> Seq Scan on public.t111 t111_1 - Output: t111_1.ctid, t111_1.tableoid, t111_1.a - Filter: (t111_1.a = 3) - -> Subquery Scan on t1_2 - Output: 100, t1_2.b, t1_2.c, t1_2.e, t1_2.ctid - Filter: snoop(t1_2.a) - -> LockRows - Output: t12_2.ctid, t12_2.a, t12_2.b, t12_2.c, t12_2.e, t12_2.ctid, t12_3.ctid, t12_3.tableoid - -> Nested Loop Semi Join - Output: t12_2.ctid, t12_2.a, t12_2.b, t12_2.c, t12_2.e, t12_2.ctid, t12_3.ctid, t12_3.tableoid - -> Seq Scan on public.t12 t12_2 - Output: t12_2.ctid, t12_2.a, t12_2.b, t12_2.c, t12_2.e - Filter: ((t12_2.a > 5) AND (t12_2.a = 3) AND leakproof(t12_2.a)) - -> Append - -> Seq Scan on public.t12 t12_3 - Output: t12_3.ctid, t12_3.tableoid, t12_3.a - Filter: (t12_3.a = 3) - -> Seq Scan on public.t111 t111_2 - Output: t111_2.ctid, t111_2.tableoid, t111_2.a - Filter: (t111_2.a = 3) - -> Subquery Scan on t1_3 - Output: 100, t1_3.b, t1_3.c, t1_3.d, t1_3.e, t1_3.ctid - Filter: snoop(t1_3.a) - -> LockRows - Output: t111_3.ctid, t111_3.a, t111_3.b, t111_3.c, t111_3.d, t111_3.e, t111_3.ctid, t12_4.ctid, t12_4.tableoid - -> Nested Loop Semi Join - Output: t111_3.ctid, t111_3.a, t111_3.b, t111_3.c, t111_3.d, t111_3.e, t111_3.ctid, t12_4.ctid, t12_4.tableoid - -> Seq Scan on public.t111 t111_3 - Output: t111_3.ctid, t111_3.a, t111_3.b, t111_3.c, t111_3.d, t111_3.e - Filter: ((t111_3.a > 5) AND (t111_3.a = 3) AND leakproof(t111_3.a)) - -> Append - -> Seq Scan on public.t12 t12_4 - Output: t12_4.ctid, t12_4.tableoid, t12_4.a - Filter: (t12_4.a = 3) - -> Seq Scan on public.t111 t111_4 - Output: t111_4.ctid, t111_4.tableoid, t111_4.a - Filter: (t111_4.a = 3) -(73 rows) - -UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a = 3; + Index Cond: ((t1.a > 5) AND (t1.a < 7)) + Filter: ((t1.a <> 6) AND (alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t1.a) AND leakproof(t1.a)) + SubPlan 1 + -> Append + -> Seq Scan on public.t12 t12_1 + Filter: (t12_1.a = t1.a) + -> Seq Scan on public.t111 t111_1 + Filter: (t111_1.a = t1.a) + SubPlan 2 + -> Append + -> Seq Scan on public.t12 t12_2 + Output: t12_2.a + -> Seq Scan on public.t111 t111_2 + Output: t111_2.a + -> Index Scan using t11_a_idx on public.t11 + Output: 100, t11.b, t11.c, t11.d, t11.ctid + Index Cond: ((t11.a > 5) AND (t11.a < 7)) + Filter: ((t11.a <> 6) AND (alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t11.a) AND leakproof(t11.a)) + -> Index Scan using t12_a_idx on public.t12 + Output: 100, t12.b, t12.c, t12.e, t12.ctid + Index Cond: ((t12.a > 5) AND (t12.a < 7)) + Filter: ((t12.a <> 6) AND (alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t12.a) AND leakproof(t12.a)) + -> Index Scan using t111_a_idx on public.t111 + Output: 100, t111.b, t111.c, t111.d, t111.e, t111.ctid + Index Cond: ((t111.a > 5) AND (t111.a < 7)) + Filter: ((t111.a <> 6) AND (alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t111.a) AND leakproof(t111.a)) +(33 rows) + +UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a < 7 AND a != 6; SELECT * FROM v1 WHERE a=100; -- Nothing should have been changed to 100 a | b | c | d ---+---+---+--- @@ -2205,82 +2147,42 @@ SELECT * FROM t1 WHERE a=100; -- Nothing should have been changed to 100 EXPLAIN (VERBOSE, COSTS OFF) UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8; - QUERY PLAN ------------------------------------------------------------------------------------------------------------------------------------- - Update on public.t1 t1_4 - Update on public.t1 t1_4 - Update on public.t11 t1 - Update on public.t12 t1 - Update on public.t111 t1 - -> Subquery Scan on t1 + QUERY PLAN +--------------------------------------------------------------------------------------------------------- + Update on public.t1 + Update on public.t1 + Update on public.t11 + Update on public.t12 + Update on public.t111 + -> Index Scan using t1_a_idx on public.t1 Output: (t1.a + 1), t1.b, t1.c, t1.ctid - Filter: snoop(t1.a) - -> LockRows - Output: t1_5.a, t1_5.ctid, t1_5.b, t1_5.c, t1_5.ctid, t12.ctid, t12.tableoid - -> Nested Loop Semi Join - Output: t1_5.a, t1_5.ctid, t1_5.b, t1_5.c, t1_5.ctid, t12.ctid, t12.tableoid - -> Seq Scan on public.t1 t1_5 - Output: t1_5.a, t1_5.ctid, t1_5.b, t1_5.c - Filter: ((t1_5.a > 5) AND (t1_5.a = 8) AND leakproof(t1_5.a)) - -> Append - -> Seq Scan on public.t12 - Output: t12.ctid, t12.tableoid, t12.a - Filter: (t12.a = 8) - -> Seq Scan on public.t111 - Output: t111.ctid, t111.tableoid, t111.a - Filter: (t111.a = 8) - -> Subquery Scan on t1_1 - Output: (t1_1.a + 1), t1_1.b, t1_1.c, t1_1.d, t1_1.ctid - Filter: snoop(t1_1.a) - -> LockRows - Output: t11.a, t11.ctid, t11.b, t11.c, t11.d, t11.ctid, t12_1.ctid, t12_1.tableoid - -> Nested Loop Semi Join - Output: t11.a, t11.ctid, t11.b, t11.c, t11.d, t11.ctid, t12_1.ctid, t12_1.tableoid - -> Seq Scan on public.t11 - Output: t11.a, t11.ctid, t11.b, t11.c, t11.d - Filter: ((t11.a > 5) AND (t11.a = 8) AND leakproof(t11.a)) - -> Append - -> Seq Scan on public.t12 t12_1 - Output: t12_1.ctid, t12_1.tableoid, t12_1.a - Filter: (t12_1.a = 8) - -> Seq Scan on public.t111 t111_1 - Output: t111_1.ctid, t111_1.tableoid, t111_1.a - Filter: (t111_1.a = 8) - -> Subquery Scan on t1_2 - Output: (t1_2.a + 1), t1_2.b, t1_2.c, t1_2.e, t1_2.ctid - Filter: snoop(t1_2.a) - -> LockRows - Output: t12_2.a, t12_2.ctid, t12_2.b, t12_2.c, t12_2.e, t12_2.ctid, t12_3.ctid, t12_3.tableoid - -> Nested Loop Semi Join - Output: t12_2.a, t12_2.ctid, t12_2.b, t12_2.c, t12_2.e, t12_2.ctid, t12_3.ctid, t12_3.tableoid - -> Seq Scan on public.t12 t12_2 - Output: t12_2.a, t12_2.ctid, t12_2.b, t12_2.c, t12_2.e - Filter: ((t12_2.a > 5) AND (t12_2.a = 8) AND leakproof(t12_2.a)) - -> Append - -> Seq Scan on public.t12 t12_3 - Output: t12_3.ctid, t12_3.tableoid, t12_3.a - Filter: (t12_3.a = 8) - -> Seq Scan on public.t111 t111_2 - Output: t111_2.ctid, t111_2.tableoid, t111_2.a - Filter: (t111_2.a = 8) - -> Subquery Scan on t1_3 - Output: (t1_3.a + 1), t1_3.b, t1_3.c, t1_3.d, t1_3.e, t1_3.ctid - Filter: snoop(t1_3.a) - -> LockRows - Output: t111_3.a, t111_3.ctid, t111_3.b, t111_3.c, t111_3.d, t111_3.e, t111_3.ctid, t12_4.ctid, t12_4.tableoid - -> Nested Loop Semi Join - Output: t111_3.a, t111_3.ctid, t111_3.b, t111_3.c, t111_3.d, t111_3.e, t111_3.ctid, t12_4.ctid, t12_4.tableoid - -> Seq Scan on public.t111 t111_3 - Output: t111_3.a, t111_3.ctid, t111_3.b, t111_3.c, t111_3.d, t111_3.e - Filter: ((t111_3.a > 5) AND (t111_3.a = 8) AND leakproof(t111_3.a)) - -> Append - -> Seq Scan on public.t12 t12_4 - Output: t12_4.ctid, t12_4.tableoid, t12_4.a - Filter: (t12_4.a = 8) - -> Seq Scan on public.t111 t111_4 - Output: t111_4.ctid, t111_4.tableoid, t111_4.a - Filter: (t111_4.a = 8) -(73 rows) + Index Cond: ((t1.a > 5) AND (t1.a = 8)) + Filter: ((alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t1.a) AND leakproof(t1.a)) + SubPlan 1 + -> Append + -> Seq Scan on public.t12 t12_1 + Filter: (t12_1.a = t1.a) + -> Seq Scan on public.t111 t111_1 + Filter: (t111_1.a = t1.a) + SubPlan 2 + -> Append + -> Seq Scan on public.t12 t12_2 + Output: t12_2.a + -> Seq Scan on public.t111 t111_2 + Output: t111_2.a + -> Index Scan using t11_a_idx on public.t11 + Output: (t11.a + 1), t11.b, t11.c, t11.d, t11.ctid + Index Cond: ((t11.a > 5) AND (t11.a = 8)) + Filter: ((alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t11.a) AND leakproof(t11.a)) + -> Index Scan using t12_a_idx on public.t12 + Output: (t12.a + 1), t12.b, t12.c, t12.e, t12.ctid + Index Cond: ((t12.a > 5) AND (t12.a = 8)) + Filter: ((alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t12.a) AND leakproof(t12.a)) + -> Index Scan using t111_a_idx on public.t111 + Output: (t111.a + 1), t111.b, t111.c, t111.d, t111.e, t111.ctid + Index Cond: ((t111.a > 5) AND (t111.a = 8)) + Filter: ((alternatives: SubPlan 1 or hashed SubPlan 2) AND snoop(t111.a) AND leakproof(t111.a)) +(33 rows) UPDATE v1 SET a=a+1 WHERE snoop(a) AND leakproof(a) AND a = 8; NOTICE: snooped value: 8 diff --git a/src/test/regress/sql/equivclass.sql b/src/test/regress/sql/equivclass.sql index 17fad673e92..0e4aa0cd2c5 100644 --- a/src/test/regress/sql/equivclass.sql +++ b/src/test/regress/sql/equivclass.sql @@ -222,3 +222,35 @@ explain (costs off) union all select ff + 4 as x from ec1) as ss1 where ss1.x = ec1.f1 and ec1.ff = 42::int8; + +-- check effects of row-level security +set enable_nestloop = on; +set enable_mergejoin = off; + +alter table ec1 enable row level security; +create policy p1 on ec1 using (f1 < '5'::int8alias1); + +create user regress_user_ectest; +grant select on ec0 to regress_user_ectest; +grant select on ec1 to regress_user_ectest; + +-- without any RLS, we'll treat {a.ff, b.ff, 43} as an EquivalenceClass +explain (costs off) + select * from ec0 a, ec1 b + where a.ff = b.ff and a.ff = 43::bigint::int8alias1; + +set session authorization regress_user_ectest; + +-- with RLS active, the non-leakproof a.ff = 43 clause is not treated +-- as a suitable source for an EquivalenceClass; currently, this is true +-- even though the RLS clause has nothing to do directly with the EC +explain (costs off) + select * from ec0 a, ec1 b + where a.ff = b.ff and a.ff = 43::bigint::int8alias1; + +reset session authorization; + +revoke select on ec0 from regress_user_ectest; +revoke select on ec1 from regress_user_ectest; + +drop user regress_user_ectest; diff --git a/src/test/regress/sql/updatable_views.sql b/src/test/regress/sql/updatable_views.sql index bb9a3a61746..ffc64d2de9a 100644 --- a/src/test/regress/sql/updatable_views.sql +++ b/src/test/regress/sql/updatable_views.sql @@ -1001,8 +1001,8 @@ SELECT * FROM v1 WHERE a=3; -- should not see anything SELECT * FROM v1 WHERE a=8; EXPLAIN (VERBOSE, COSTS OFF) -UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a = 3; -UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a = 3; +UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a < 7 AND a != 6; +UPDATE v1 SET a=100 WHERE snoop(a) AND leakproof(a) AND a < 7 AND a != 6; SELECT * FROM v1 WHERE a=100; -- Nothing should have been changed to 100 SELECT * FROM t1 WHERE a=100; -- Nothing should have been changed to 100 |