-- ============================================ -- Fix RLS Infinite Recursion -- ============================================ -- This script breaks the circular dependency between bottle_splits -- and split_participants RLS policies using SECURITY DEFINER functions. -- ============================================ -- 1. Create Security Definer functions to bypass RLS CREATE OR REPLACE FUNCTION public.check_is_split_host(check_split_id UUID, check_user_id UUID) RETURNS BOOLEAN AS $$ BEGIN RETURN EXISTS ( SELECT 1 FROM public.bottle_splits WHERE id = check_split_id AND host_id = check_user_id ); END; $$ LANGUAGE plpgsql SECURITY DEFINER; CREATE OR REPLACE FUNCTION public.check_is_split_participant(check_split_id UUID, check_user_id UUID) RETURNS BOOLEAN AS $$ BEGIN RETURN EXISTS ( SELECT 1 FROM public.split_participants WHERE split_id = check_split_id AND user_id = check_user_id ); END; $$ LANGUAGE plpgsql SECURITY DEFINER; -- 2. Update bottle_splits policies DROP POLICY IF EXISTS "bottle_splits_participant_view" ON bottle_splits; DROP POLICY IF EXISTS "bottle_splits_host_policy" ON bottle_splits; CREATE POLICY "bottle_splits_host_policy" ON bottle_splits FOR ALL USING ((SELECT auth.uid()) = host_id); CREATE POLICY "bottle_splits_participant_view" ON bottle_splits FOR SELECT USING ( check_is_split_participant(id, (SELECT auth.uid())) ); -- 3. Update split_participants policies DROP POLICY IF EXISTS "split_participants_host_policy" ON split_participants; DROP POLICY IF EXISTS "split_participants_own_policy" ON split_participants; CREATE POLICY "split_participants_own_policy" ON split_participants FOR ALL USING ((SELECT auth.uid()) = user_id); CREATE POLICY "split_participants_host_policy" ON split_participants FOR ALL USING ( check_is_split_host(split_id, (SELECT auth.uid())) ); -- Note: bottle_splits_public_view and split_participants_public_view -- don't cause recursion as they don't cross-reference tables in a cycle.