create function public.withdraw_contribution(p_dataset uuid,p_owner uuid) returns void language plpgsql security invoker set search_path='' as $$ declare parent uuid; d public.datasets; begin select parent_dataset_id into parent from public.datasets where id=p_dataset and owner_id=p_owner; if parent is null then raise exception 'Contribution not found'; end if; perform 1 from public.datasets where id=parent for update; -- Match the worker's job-before-dataset lock order. perform 1 from public.upload_jobs where dataset_id=p_dataset for update; select * into d from public.datasets where id=p_dataset and owner_id=p_owner for update; if d.contribution_status not in ('pending','submitted') then raise exception 'Only pending contributions can be withdrawn'; end if; update public.upload_jobs set state='cancelled',updated_at=now() where dataset_id=p_dataset and state in ('queued','running'); update public.datasets set state='failed',contribution_status='rejected',rejection_reason='Withdrawn by contributor',updated_at=now() where id=p_dataset; end; $$; revoke execute on function public.withdraw_contribution(uuid,uuid) from public,anon,authenticated; grant execute on function public.withdraw_contribution(uuid,uuid) to service_role;