Come on, admit it: you've always wanted to display the infomask bits from a tuple header in a human-readable manner, but you've never gotten around to it and you still keep htup.h in display while you peek around tuples.
Fortunately, that time is now past! Here's a short and simple recipe to decode the bits for your reading pleasure. Gone is the htup.h cheat sheet. Here's what you need:
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; $$;You can now use it like this:
alvherre=# select lp, t_xmin, t_xmax, t_ctid, infomask(t_infomask, 1) as infomask, infomask(t_infomask2, 2) as infomask2 from heap_page_items(get_raw_page('foo', 0));
lp | t_xmin | t_xmax | t_ctid | infomask | infomask2 |
---|---|---|---|---|---|
1 | 702 | 2 | (0,2) | XMAX_IS_MULTI|XMAX_COMMITTED|XMIN_COMMITTED|XMAX_KEYSHR_LOCK | UPDATE_KEY_INTACT|HOT_UPDATED |
2 | 704 | 704 | (0,3) | UPDATED|XMAX_COMMITTED|XMIN_COMMITTED|COMBOCID | UPDATE_KEY_INTACT|HOT_UPDATED|HEAP_ONLY_TUPLE |
3 | 704 | 0 | (0,3) | UPDATED|XMAX_INVALID|XMIN_COMMITTED | HEAP_ONLY_TUPLE |
Okay, I cheated -- there are bits here that are not part of stock Postgres, but are part of my keylocks patch. It's trivial to edit them out (just make sure you remember to change HEAP_IS_NOT_UPDATE to HEAP_SHARE_LOCK).