create type infomask_bit_desc as (mask varbit, symbol text);
create or replace function infomask(msk int, which int) returns text
language plpgsql as $$
declare
        r infomask_bit_desc;
        str text = '';
        append_bar bool = false;
begin
        for r in select * from infomask_bits(which) loop
                if (msk::bit(16) & r.mask)::int <> 0 then
                        if append_bar then
                                str = str || '|';
                        end if;
                        append_bar = true;
                        str = str || r.symbol;
                end if;
        end loop;
        return str;
end;
$$ ;
create or replace function infomask_bits(which int)
returns setof infomask_bit_desc
language plpgsql as $$
begin
        if which = 1 then
                return query values
                (x'8000'::varbit, 'MOVED_IN'),
                (x'4000', 'MOVED_OFF'),
                (x'2000', 'UPDATED'),
                (x'1000', 'XMAX_IS_MULTI'),
                (x'0800', 'XMAX_INVALID'),
                (x'0400', 'XMAX_COMMITTED'),
                (x'0200', 'XMIN_INVALID'),
                (x'0100', 'XMIN_COMMITTED'),
                (x'0080', 'XMAX_LOCK_ONLY'),
                (x'0040', 'EXCL_LOCK'),
                (x'0020', 'COMBOCID'),
                (x'0010', 'XMAX_KEYSHR_LOCK'),
                (x'0008', 'HASOID'),
                (x'0004', 'HASEXTERNAL'),
                (x'0002', 'HASVARWIDTH'),
                (x'0001', 'HASNULL');
        elsif which = 2 then
                return query values
                (x'2000'::varbit, 'UPDATE_KEY_REVOKED'),
                (x'4000', 'HOT_UPDATED'),
                (x'8000', 'HEAP_ONLY_TUPLE');
        end if;
end;
$$;

create extension if not exists pageinspect;
