perf(rls): wrap RLS policy functions in (select ...) for per-statement evaluation#3
Conversation
|
Thanks for this — nicely researched, and the InitPlan pattern is exactly right. I checked it against the schema and the migration plumbing (placement, filename ordering, and the runner wrapping each file in its own transaction all check out), and it's predicate-equivalent so row visibility is unchanged. One thing before I merge: every one of these policies is defined with both a Could you extend each statement to set both clauses? e.g. ALTER POLICY courses_user_isolation ON public.courses
USING (user_id = (SELECT current_setting('app.user_id', true))::uuid)
WITH CHECK (user_id = (SELECT current_setting('app.user_id', true))::uuid);Filename and placement are fine as-is. Thanks again! |
|
Done -- updated to set both clauses on all 16 policies. You nailed it: And your hunch about the "PERF001 -> 0" claim was spot-on -- pgrls's PERF001 was only scanning |
|
Perfect — both clauses wrapped on all 16 policies, still predicate-equivalent, and the migration ordering/runner are happy. And thanks for fixing PERF001 upstream to cover |
|
Thanks for merging, and for the thorough review — the kind that genuinely makes a contribution better. This came out of pgrls, an open-source Postgres RLS linter/verifier, and your |
|
Thanks again! I'll keep pgrls in mind — RLS here is currently inert (bypass role) so CI coverage isn't pressing yet, but I may take you up on that when we flip it on. Good luck with the project! |
Closes #2.
The per-user / per-tenant RLS policies call their session function (
auth.uid()/current_setting(...)) directly inUSING/WITH CHECK, which Postgres re-evaluates once per row. This wraps each call in a scalar subquery so the planner evaluates it once per statement (an InitPlan) and caches it — the optimization Supabase documents for RLS.(select f())returns the same value, so row visibility is unchanged.20260517000000_wrap_rls_perf_initplan.sql); the SQL ispgrls fix --rule PERF001output.Happy to adjust the migration filename/placement to your conventions.