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).