set search_path = app, public; create or replace function app.verify_chain(p_shop uuid) returns table (txn_id uuid, reference_no bigint, ok boolean) language plpgsql security definer set search_path = app, public stable as $$ declare prev bytea; rec app.transactions%rowtype; begin if auth.uid() is not null and not app.has_role_in_shop(p_shop, 'owner') and not app.has_role_in_shop(p_shop, 'auditor') then raise exception 'not authorized'; end if; prev := null; for rec in select * from app.transactions where shop_id = p_shop order by reference_no loop txn_id := rec.id; reference_no := rec.reference_no; ok := (rec.prev_row_hash is not distinct from prev) and (rec.row_hash = app.txn_compute_hash(rec, prev)); prev := rec.row_hash; return next; end loop; end; $$; revoke all on function app.verify_chain(uuid) from public; grant execute on function app.verify_chain(uuid) to authenticated;