Skip to content

Commit 81bc843

Browse files
tglsfdcCommitfest Bot
authored and
Commitfest Bot
committed
Add a test case showing undesirable RLS behavior in SQL functions.
In the historical implementation of SQL functions, once we have built a set of plans for a SQL function we'll continue to use them during subsequent function invocations in the same query. This isn't ideal, and this somewhat-contrived test case shows one reason why not: we don't notice changes in RLS-relevant state. I'm putting this as a separate patch in the series so that the change in behavior will be apparent. Author: Alexander Pyhalov <[email protected]> Reviewed-by: Tom Lane <[email protected]> Discussion: https://postgr.es/m/8216639.NyiUUSuA9g@aivenlaptop
1 parent 8c85086 commit 81bc843

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed

src/test/regress/expected/rowsecurity.out

+59
Original file line numberDiff line numberDiff line change
@@ -4695,6 +4695,65 @@ RESET ROLE;
46954695
DROP FUNCTION rls_f();
46964696
DROP VIEW rls_v;
46974697
DROP TABLE rls_t;
4698+
-- Check that RLS changes invalidate SQL function plans
4699+
create table rls_t (c text);
4700+
create table test_t (c text);
4701+
insert into rls_t values ('a'), ('b'), ('c'), ('d');
4702+
insert into test_t values ('a'), ('b');
4703+
alter table rls_t enable row level security;
4704+
grant select on rls_t to regress_rls_alice;
4705+
grant select on test_t to regress_rls_alice;
4706+
create policy p1 on rls_t for select to regress_rls_alice
4707+
using (c = current_setting('rls_test.blah'));
4708+
-- Function changes row_security setting and so invalidates plan
4709+
create function rls_f(text) returns text
4710+
begin atomic
4711+
select set_config('rls_test.blah', $1, true) || set_config('row_security', 'false', true) || string_agg(c, ',' order by c) from rls_t;
4712+
end;
4713+
set plan_cache_mode to force_custom_plan;
4714+
-- Table owner bypasses RLS
4715+
select rls_f(c) from test_t order by rls_f;
4716+
rls_f
4717+
-------------
4718+
aoffa,b,c,d
4719+
boffa,b,c,d
4720+
(2 rows)
4721+
4722+
-- For other users, changes in row_security setting
4723+
-- should lead to RLS error during query rewrite
4724+
set role regress_rls_alice;
4725+
select rls_f(c) from test_t order by rls_f;
4726+
rls_f
4727+
-------
4728+
boffa
4729+
4730+
(2 rows)
4731+
4732+
reset role;
4733+
set plan_cache_mode to force_generic_plan;
4734+
-- Table owner bypasses RLS, although cached plan will be invalidated
4735+
select rls_f(c) from test_t order by rls_f;
4736+
rls_f
4737+
-------------
4738+
aoffa,b,c,d
4739+
boffa,b,c,d
4740+
(2 rows)
4741+
4742+
-- For other users, changes in row_security setting
4743+
-- should lead to plan invalidation and RLS error during query rewrite
4744+
set role regress_rls_alice;
4745+
select rls_f(c) from test_t order by rls_f;
4746+
rls_f
4747+
-------
4748+
boffa
4749+
4750+
(2 rows)
4751+
4752+
reset role;
4753+
reset plan_cache_mode;
4754+
reset rls_test.blah;
4755+
drop function rls_f(text);
4756+
drop table rls_t, test_t;
46984757
--
46994758
-- Clean up objects
47004759
--

src/test/regress/sql/rowsecurity.sql

+44
Original file line numberDiff line numberDiff line change
@@ -2307,6 +2307,50 @@ DROP FUNCTION rls_f();
23072307
DROP VIEW rls_v;
23082308
DROP TABLE rls_t;
23092309

2310+
-- Check that RLS changes invalidate SQL function plans
2311+
create table rls_t (c text);
2312+
create table test_t (c text);
2313+
insert into rls_t values ('a'), ('b'), ('c'), ('d');
2314+
insert into test_t values ('a'), ('b');
2315+
alter table rls_t enable row level security;
2316+
grant select on rls_t to regress_rls_alice;
2317+
grant select on test_t to regress_rls_alice;
2318+
create policy p1 on rls_t for select to regress_rls_alice
2319+
using (c = current_setting('rls_test.blah'));
2320+
2321+
-- Function changes row_security setting and so invalidates plan
2322+
create function rls_f(text) returns text
2323+
begin atomic
2324+
select set_config('rls_test.blah', $1, true) || set_config('row_security', 'false', true) || string_agg(c, ',' order by c) from rls_t;
2325+
end;
2326+
2327+
set plan_cache_mode to force_custom_plan;
2328+
2329+
-- Table owner bypasses RLS
2330+
select rls_f(c) from test_t order by rls_f;
2331+
2332+
-- For other users, changes in row_security setting
2333+
-- should lead to RLS error during query rewrite
2334+
set role regress_rls_alice;
2335+
select rls_f(c) from test_t order by rls_f;
2336+
reset role;
2337+
2338+
set plan_cache_mode to force_generic_plan;
2339+
2340+
-- Table owner bypasses RLS, although cached plan will be invalidated
2341+
select rls_f(c) from test_t order by rls_f;
2342+
2343+
-- For other users, changes in row_security setting
2344+
-- should lead to plan invalidation and RLS error during query rewrite
2345+
set role regress_rls_alice;
2346+
select rls_f(c) from test_t order by rls_f;
2347+
reset role;
2348+
2349+
reset plan_cache_mode;
2350+
reset rls_test.blah;
2351+
drop function rls_f(text);
2352+
drop table rls_t, test_t;
2353+
23102354
--
23112355
-- Clean up objects
23122356
--

0 commit comments

Comments
 (0)