Concepts¶
This page explains the ideas behind the functions. Read it once, then use the function reference as a lookup table.
Checksum levels¶
The extension works at six levels:
| Level | Physical | Logical | Typical question |
|---|---|---|---|
| Page | yes | — | Is this one storage page intact? |
| Cell | — | yes | Does this one value have the expected hash? |
| Tuple | yes | yes | Does this row still match its expected bytes or content? |
| Table | yes | yes | Did the table’s storage or logical content change? |
| Index | yes | yes | Is the physical index intact, or does it contain the expected entries? |
| Database | yes | yes | Did anything in the database change? |
Page checksums are PostgreSQL’s built-in page checksum. Page-level 64-bit checksums do not exist in this extension; the other levels have both physical and logical forms.
Logical vs physical¶
Logical checksums¶
A logical checksum is a fingerprint of data content. It deliberately excludes:
- heap TIDs and tuple locations;
- relation and type OIDs;
- page layout and MVCC headers;
- physical row order.
It is stable across VACUUM, VACUUM FULL, CLUSTER, REINDEX, dump/restore
and OID changes. That makes it suitable for:
- comparing a primary and a replica;
- checking data after a restore or migration;
- detecting logical data changes in CI;
- comparing the same schema in two databases.
A primary key is not required. Duplicate rows are preserved by a sum plus count aggregate, so two identical rows contribute twice.
Physical checksums¶
A physical checksum is a fingerprint of one cluster’s storage. It includes physical locations, tuple headers, MVCC fields, page/index bytes and relation storage identity. It changes after:
VACUUM FULL,CLUSTERor a table rewrite;REINDEX;- moving a tuple to another block or offset;
- changing the relation’s relfilenode or tablespace.
Use physical checksums to detect on-disk corruption or to confirm that a maintenance operation changed exactly what you expected. Do not compare physical checksums between different clusters, replicas or databases.
A simple rule¶
| You want to know... | Use |
|---|---|
| Has the data changed? | logical |
| Has this cluster’s storage changed? | physical |
| Is an index entry missing or corrupt? | physical index |
| Does the index logically match the table? | logical index |
Which API should I use?¶
The extension provides two forms of the same functions.
Default 32-bit API¶
The default functions use FNV-1a 32-bit and return an ordinary SQL integer
or bigint:
SELECT pg_table_logical_checksum('orders'::regclass);
SELECT pg_table_physical_checksum('orders'::regclass, false);
This is the simplest interface and the right default for most users. A 32-bit checksum is sufficient for detecting accidental data changes and corruption; it is also the format used by v1 CLI baselines.
Optional 64-bit API¶
The generic overloads take an algorithm name and return raw bytea:
SELECT pg_table_logical_checksum('orders'::regclass, 'fnv64');
SELECT pg_table_logical_checksum('orders'::regclass, 'fnv32');
Choose this form when you need:
- a wider 64-bit digest (
fnv64); - an explicit algorithm in the call;
- a cross-system format that is not tied to a SQL integer type;
- a v2 CLI baseline.
Digests are big-endian bytes: fnv32 is 4 bytes and fnv64 is 8 bytes.
Table and database physical checksums always return 8 bytes because the
relation/database identity is part of the value.
The 32-bit and 64-bit paths share the same canonical value handling and aggregation rules. A 64-bit digest is wider, but FNV-1a remains a non-cryptographic checksum.
Converting a digest to bigint¶
SELECT pg_checksum_bigint(pg_table_logical_checksum('orders'::regclass, 'fnv64'));
For 4-byte fnv32 digests, the one-argument form sign-extends. Use
pg_checksum_bigint(digest, true) when you need the unsigned value (for
example, to compare with a table logical checksum from the default API).
The detailed signatures are in the function reference.
How aggregation works¶
Table, index and database checksums are order-independent:
- physical aggregates combine hashes with XOR;
- logical aggregates use sum plus count.
The count is important: a pure XOR would cancel duplicate rows.
Parallel workers split the scan by blocks or relations and the leader combines
their partial results. With pg_integrity_checksums.workers > 0, serial and
parallel executions produce identical checksums, for both 32-bit and 64-bit
paths.
Baseline formats¶
The CLI stores a snapshot in a versioned JSON baseline.
| Format | Algorithm | Written by |
|---|---|---|
v1 |
FNV-1a 32-bit | capture by default |
v2 |
explicit hash (fnv32 or fnv64) |
capture --hash fnv64 |
verify and update inherit the algorithm from the baseline they read.
Older CLI releases reject v2 instead of comparing incompatible digests.
See CLI baseline formats.
What this is not¶
- FNV-1a is not cryptographic. It detects accidental changes, not a malicious attacker who can recompute the hash.
- Physical checksums are tied to one cluster and database.
- Logical checksums describe content, not physical layout.
- The extension does not replace backups,
pg_checksumsoramcheck.
Permissions and safety¶
Table, page, cell, tuple and index checksums read relation storage directly:
- they require
SELECTon the relation (or the base table for an index); - relations with row-level security are rejected, because a direct heap scan cannot apply RLS policies;
- database-level functions require superuser.
Capture and verify take one repeatable-read, read-only snapshot. The CLI never modifies application data.
Read next¶
- Getting started — run your first checksum.
- Function reference — exact signatures and return types.
- Operations — limitations, performance and use cases.
- Troubleshooting — common errors.