# Infomask decoder

The flags in a heap tuple’s t_infomask and t_infomask2, as pageinspect’s heap_page_items() prints them.

> Canonical URL: https://sudohulk.com/tools/infomask
> Agrees with: `heap_tuple_infomask_flags()`, PostgreSQL 18.3, and is tested against its output
> WebMCP tool: `decode_infomask`

---

Inputs: `t_infomask` (default 2306), `t_infomask2` (default 3).

For example, t_infomask 2306, t_infomask2 3: raw_flags {HEAP_HASVARWIDTH,HEAP_XMIN_COMMITTED,HEAP_XMAX_INVALID}, combined_flags {}, 3 attribute(s).

## How it is worked out

```text
raw_flags      = every bit set, t_infomask first, then t_infomask2
combined_flags = each two-bit state with both bits set
natts          = t_infomask2 & 0x07FF
```

Every tuple header carries two 16-bit fields. `t_infomask` says what the tuple holds (nulls, variable-width values, values stored out of line) and what is known about its `xmin` and `xmax`; `t_infomask2` has three flags in its top bits and the number of attributes in its low 11.

The hint bits (`HEAP_XMIN_COMMITTED` and the other three) are set by whoever first looks up a transaction in `pg_xact`, often a plain `SELECT`. The same row can show a different `t_infomask` before and after it is read.

`HEAP_MOVED_OFF` and `HEAP_MOVED_IN` date from VACUUM FULL before 9.0. Nothing sets them now; they are still read, for clusters upgraded with pg_upgrade.

pageinspect prints the two fields as integers, `heap_page_items()` included; the names come from `heap_tuple_infomask_flags()`, which this follows flag for flag.

The same answer from a server:

```sql
SELECT * FROM heap_tuple_infomask_flags(2306, 3);
```
