30#include "utils/fmgroids.h"
36#define HEAPCHECK_RELATION_COLS 4
39#define VARLENA_SIZE_LIMIT 0x3FFFFFFF
183 void *callback_private_data,
184 void *per_buffer_data);
187 bool *xmin_commit_status_ok,
199 bool *xmin_commit_status_ok,
272 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
273 errmsg(
"relation cannot be null")));
278 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
279 errmsg(
"on_error_stop cannot be null")));
284 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
285 errmsg(
"check_toast cannot be null")));
290 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
291 errmsg(
"skip cannot be null")));
301 (
errcode(ERRCODE_INVALID_PARAMETER_VALUE),
302 errmsg(
"invalid skip option"),
303 errhint(
"Valid skip options are \"all-visible\", \"all-frozen\", and \"none\".")));
333 if (!RELKIND_HAS_TABLE_AM(ctx.
rel->
rd_rel->relkind) &&
334 ctx.
rel->
rd_rel->relkind != RELKIND_SEQUENCE)
336 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
337 errmsg(
"cannot check relation \"%s\"",
345 if (ctx.
rel->
rd_rel->relkind != RELKIND_SEQUENCE &&
346 ctx.
rel->
rd_rel->relam != HEAP_TABLE_AM_OID)
348 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
349 errmsg(
"only heap AM is supported")));
356 if (ctx.
rel->
rd_rel->relpersistence == RELPERSISTENCE_UNLOGGED &&
360 (
errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
361 errmsg(
"cannot verify unlogged relation \"%s\" during recovery, skipping",
389 errmsg(
"starting block number must be between 0 and %u",
402 errmsg(
"ending block number must be between 0 and %u",
529 psprintf(
"line pointer redirection to item at offset %d precedes minimum offset %d",
537 psprintf(
"line pointer redirection to item at offset %d exceeds maximum offset %d",
553 psprintf(
"redirected line pointer points to an unused item at offset %d",
560 psprintf(
"redirected line pointer points to a dead item at offset %d",
567 psprintf(
"redirected line pointer points to another redirected line pointer at offset %d",
589 psprintf(
"line pointer to page offset %u is not maximally aligned",
596 psprintf(
"line pointer length %u is less than the minimum tuple header size %u",
604 psprintf(
"line pointer to page offset %u with length %u ends beyond maximum page offset %d",
681 psprintf(
"redirected line pointer points to a non-heap-only tuple at offset %d",
689 psprintf(
"redirect line pointer points to offset %d, but offset %d also points there",
722 psprintf(
"tuple points to new version at offset %d, but offset %d also points there",
746 psprintf(
"non-heap-only update produced a heap-only tuple at offset %d",
753 psprintf(
"heap-only update produced a non-heap only tuple at offset %d",
775 psprintf(
"tuple with in-progress xmin %u was updated to produce a tuple at offset %d with committed xmin %u",
791 psprintf(
"tuple with aborted xmin %u was updated to produce a tuple at offset %d with in-progress xmin %u",
797 psprintf(
"tuple with aborted xmin %u was updated to produce a tuple at offset %d with committed xmin %u",
831 psprintf(
"tuple is root of chain but is marked as heap-only tuple"));
882 void *callback_private_data,
883 void *per_buffer_data)
971 ta->offnum,
ta->attnum, msg);
1010 psprintf(
"data begins at offset %u beyond the tuple length %u",
1019 pstrdup(
"multixact should not be marked committed"));
1033 psprintf(
"tuple has been HOT updated, but xmax is 0"));
1046 psprintf(
"tuple is heap only, but not the result of an update"));
1059 psprintf(
"tuple data should begin at byte %u, but actually begins at byte %u (1 attribute, has nulls)",
1063 psprintf(
"tuple data should begin at byte %u, but actually begins at byte %u (%u attributes, has nulls)",
1065 else if (ctx->
natts == 1)
1067 psprintf(
"tuple data should begin at byte %u, but actually begins at byte %u (1 attribute, no nulls)",
1071 psprintf(
"tuple data should begin at byte %u, but actually begins at byte %u (%u attributes, no nulls)",
1139 psprintf(
"xmin %u equals or exceeds next valid transaction ID %u:%u",
1146 psprintf(
"xmin %u precedes oldest valid transaction ID %u:%u",
1153 psprintf(
"xmin %u precedes relation freeze threshold %u:%u",
1176 pstrdup(
"old-style VACUUM FULL transaction ID for moved off tuple is invalid"));
1180 psprintf(
"old-style VACUUM FULL transaction ID %u for moved off tuple equals or exceeds next valid transaction ID %u:%u",
1187 psprintf(
"old-style VACUUM FULL transaction ID %u for moved off tuple precedes relation freeze threshold %u:%u",
1194 psprintf(
"old-style VACUUM FULL transaction ID %u for moved off tuple precedes oldest valid transaction ID %u:%u",
1207 psprintf(
"old-style VACUUM FULL transaction ID %u for moved off tuple matches our current transaction ID",
1212 psprintf(
"old-style VACUUM FULL transaction ID %u for moved off tuple appears to be in progress",
1245 pstrdup(
"old-style VACUUM FULL transaction ID for moved in tuple is invalid"));
1249 psprintf(
"old-style VACUUM FULL transaction ID %u for moved in tuple equals or exceeds next valid transaction ID %u:%u",
1256 psprintf(
"old-style VACUUM FULL transaction ID %u for moved in tuple precedes relation freeze threshold %u:%u",
1263 psprintf(
"old-style VACUUM FULL transaction ID %u for moved in tuple precedes oldest valid transaction ID %u:%u",
1276 psprintf(
"old-style VACUUM FULL transaction ID %u for moved in tuple matches our current transaction ID",
1281 psprintf(
"old-style VACUUM FULL transaction ID %u for moved in tuple appears to be in progress",
1348 pstrdup(
"multitransaction ID is invalid"));
1352 psprintf(
"multitransaction ID %u precedes relation minimum multitransaction ID threshold %u",
1357 psprintf(
"multitransaction ID %u precedes oldest valid multitransaction ID threshold %u",
1362 psprintf(
"multitransaction ID %u equals or exceeds next valid multitransaction ID %u",
1406 pstrdup(
"update xid is invalid"));
1410 psprintf(
"update xid %u equals or exceeds next valid transaction ID %u:%u",
1417 psprintf(
"update xid %u precedes relation freeze threshold %u:%u",
1424 psprintf(
"update xid %u precedes oldest valid transaction ID %u:%u",
1475 psprintf(
"xmax %u equals or exceeds next valid transaction ID %u:%u",
1482 psprintf(
"xmax %u precedes relation freeze threshold %u:%u",
1489 psprintf(
"xmax %u precedes oldest valid transaction ID %u:%u",
1571 psprintf(
"toast value %u has toast chunk with null sequence number",
1572 ta->toast_pointer.va_valueid));
1579 psprintf(
"toast value %u index scan returned chunk %d when expecting chunk %d",
1580 ta->toast_pointer.va_valueid,
1591 psprintf(
"toast value %u chunk %d has null data",
1592 ta->toast_pointer.va_valueid,
1611 psprintf(
"toast value %u chunk %d has invalid varlena header %0x",
1612 ta->toast_pointer.va_valueid,
1623 psprintf(
"toast value %u chunk %d follows last expected chunk %d",
1624 ta->toast_pointer.va_valueid,
1634 psprintf(
"toast value %u chunk %d has size %u, but expected size %u",
1635 ta->toast_pointer.va_valueid,
1677 psprintf(
"attribute with length %u starts at offset %u beyond total tuple length %u",
1697 psprintf(
"attribute with length %u ends at offset %u beyond total tuple length %u",
1729 psprintf(
"toasted attribute has unexpected TOAST tag %u",
1743 psprintf(
"attribute with length %u ends at offset %u beyond total tuple length %u",
1778 psprintf(
"toast value %u rawsize %d exceeds limit %d",
1806 psprintf(
"toast value %u has invalid compression method id %d",
1814 psprintf(
"toast value %u is external but tuple header flag HEAP_HASEXTERNAL not set",
1823 psprintf(
"toast value %u is external but relation has no toast relation",
1868 int32 last_chunk_seq;
1901 psprintf(
"toast value %u not found in toast table",
1902 ta->toast_pointer.va_valueid));
1905 psprintf(
"toast value %u was expected to end at chunk %d, but ended while expecting chunk %d",
1906 ta->toast_pointer.va_valueid,
1945 psprintf(
"number of attributes %u exceeds maximum %u expected for table",
#define InvalidBlockNumber
static Datum values[MAXATTR]
BlockNumber BufferGetBlockNumber(Buffer buffer)
void ReleaseBuffer(Buffer buffer)
void UnlockReleaseBuffer(Buffer buffer)
#define RelationGetNumberOfBlocks(reln)
static Page BufferGetPage(Buffer buffer)
static void LockBuffer(Buffer buffer, BufferLockMode mode)
static bool BufferIsValid(Buffer bufnum)
static ItemId PageGetItemId(Page page, OffsetNumber offsetNumber)
static void * PageGetItem(PageData *page, const ItemIdData *itemId)
static OffsetNumber PageGetMaxOffsetNumber(const PageData *page)
#define CStringGetTextDatum(s)
#define Assert(condition)
TransactionId MultiXactId
#define VARATT_EXTERNAL_GET_POINTER(toast_pointer, attr)
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
#define palloc0_object(type)
#define PG_GETARG_TEXT_PP(n)
#define PG_GETARG_INT64(n)
#define PG_FUNCTION_INFO_V1(funcname)
#define PG_GETARG_BOOL(n)
BufferAccessStrategy GetAccessStrategy(BufferAccessStrategyType btype)
void InitMaterializedSRF(FunctionCallInfo fcinfo, bits32 flags)
SysScanDesc systable_beginscan_ordered(Relation heapRelation, Relation indexRelation, Snapshot snapshot, int nkeys, ScanKey key)
void systable_endscan_ordered(SysScanDesc sysscan)
HeapTuple systable_getnext_ordered(SysScanDesc sysscan, ScanDirection direction)
TransactionId HeapTupleGetUpdateXid(const HeapTupleHeaderData *tup)
#define TOAST_MAX_CHUNK_SIZE
HeapTuple heap_form_tuple(TupleDesc tupleDescriptor, const Datum *values, const bool *isnull)
HeapTupleHeaderData * HeapTupleHeader
#define HeapTupleHeaderGetNatts(tup)
#define SizeofHeapTupleHeader
static bool HEAP_XMAX_IS_LOCKED_ONLY(uint16 infomask)
static int BITMAPLEN(int NATTS)
static bool HeapTupleHeaderXminInvalid(const HeapTupleHeaderData *tup)
static TransactionId HeapTupleHeaderGetXvac(const HeapTupleHeaderData *tup)
static TransactionId HeapTupleHeaderGetRawXmax(const HeapTupleHeaderData *tup)
static bool HeapTupleHeaderIsHeapOnly(const HeapTupleHeaderData *tup)
#define HEAP_XMAX_IS_MULTI
#define HEAP_XMAX_COMMITTED
static TransactionId HeapTupleHeaderGetXmin(const HeapTupleHeaderData *tup)
static bool HeapTupleHeaderIsHotUpdated(const HeapTupleHeaderData *tup)
#define HEAP_XMAX_INVALID
static TransactionId HeapTupleHeaderGetUpdateXid(const HeapTupleHeaderData *tup)
static Datum fastgetattr(HeapTuple tup, int attnum, TupleDesc tupleDesc, bool *isnull)
static bool HeapTupleHeaderXminCommitted(const HeapTupleHeaderData *tup)
#define ItemIdGetLength(itemId)
#define ItemIdIsNormal(itemId)
#define ItemIdGetOffset(itemId)
#define ItemIdGetRedirect(itemId)
#define ItemIdIsDead(itemId)
#define ItemIdIsUsed(itemId)
#define ItemIdIsRedirected(itemId)
static OffsetNumber ItemPointerGetOffsetNumber(const ItemPointerData *pointer)
static BlockNumber ItemPointerGetBlockNumber(const ItemPointerData *pointer)
List * lappend(List *list, void *datum)
void list_free_deep(List *list)
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
void LWLockRelease(LWLock *lock)
char * pstrdup(const char *in)
void pfree(void *pointer)
#define CHECK_FOR_INTERRUPTS()
void ReadMultiXactIdRange(MultiXactId *oldest, MultiXactId *next)
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
bool MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
#define InvalidOffsetNumber
#define OffsetNumberNext(offsetNumber)
#define FirstOffsetNumber
static const struct exclude_list_item skip[]
int errdetail_relkind_not_supported(char relkind)
int pg_strcasecmp(const char *s1, const char *s2)
static Datum Int64GetDatum(int64 X)
static Datum ObjectIdGetDatum(Oid X)
static Pointer DatumGetPointer(Datum X)
static Datum Int32GetDatum(int32 X)
static int32 DatumGetInt32(Datum X)
bool TransactionIdIsInProgress(TransactionId xid)
char * psprintf(const char *fmt,...)
Buffer read_stream_next_buffer(ReadStream *stream, void **per_buffer_data)
ReadStream * read_stream_begin_relation(int flags, BufferAccessStrategy strategy, Relation rel, ForkNumber forknum, ReadStreamBlockNumberCB callback, void *callback_private_data, size_t per_buffer_data_size)
void read_stream_end(ReadStream *stream)
BlockNumber block_range_read_stream_cb(ReadStream *stream, void *callback_private_data, void *per_buffer_data)
#define READ_STREAM_USE_BATCHING
BlockNumber(* ReadStreamBlockNumberCB)(ReadStream *stream, void *callback_private_data, void *per_buffer_data)
#define READ_STREAM_DEFAULT
#define READ_STREAM_SEQUENTIAL
#define RelationGetDescr(relation)
#define RelationGetRelationName(relation)
void ScanKeyInit(ScanKey entry, AttrNumber attributeNumber, StrategyNumber strategy, RegProcedure procedure, Datum argument)
Snapshot GetTransactionSnapshot(void)
void relation_close(Relation relation, LOCKMODE lockmode)
Relation relation_open(Oid relationId, LOCKMODE lockmode)
#define BTEqualStrategyNumber
BlockNumber last_exclusive
BlockNumber current_blocknum
Tuplestorestate * tupstore
bool tuple_could_be_pruned
FullTransactionId oldest_fxid
BufferAccessStrategy bstrategy
TransactionId relfrozenxid
FullTransactionId next_fxid
List * toasted_attributes
FullTransactionId relfrozenfxid
Relation valid_toast_index
XidCommitStatus cached_status
BlockRangeReadStreamPrivate range
Tuplestorestate * setResult
struct varatt_external toast_pointer
FullTransactionId nextXid
TransactionId oldestClogXid
void table_close(Relation relation, LOCKMODE lockmode)
Relation table_open(Oid relationId, LOCKMODE lockmode)
@ TOAST_INVALID_COMPRESSION_ID
@ TOAST_LZ4_COMPRESSION_ID
@ TOAST_PGLZ_COMPRESSION_ID
void toast_close_indexes(Relation *toastidxs, int num_indexes, LOCKMODE lock)
int toast_open_indexes(Relation toastrel, LOCKMODE lock, Relation **toastidxs, int *num_indexes)
Snapshot get_toast_snapshot(void)
#define TOAST_COMPRESS_METHOD(ptr)
bool TransactionIdDidCommit(TransactionId transactionId)
#define FullTransactionIdIsNormal(x)
#define FrozenTransactionId
#define InvalidTransactionId
#define FullTransactionIdPrecedesOrEquals(a, b)
#define EpochFromFullTransactionId(x)
#define U64FromFullTransactionId(x)
static FullTransactionId FullTransactionIdFromU64(uint64 value)
#define TransactionIdEquals(id1, id2)
#define BootstrapTransactionId
#define XidFromFullTransactionId(x)
#define FirstNormalTransactionId
#define TransactionIdIsValid(xid)
static FullTransactionId FullTransactionIdFromEpochAndXid(uint32 epoch, TransactionId xid)
#define TransactionIdIsNormal(xid)
#define FirstNormalFullTransactionId
#define FullTransactionIdPrecedes(a, b)
static bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
static CompactAttribute * TupleDescCompactAttr(TupleDesc tupdesc, int i)
void tuplestore_puttuple(Tuplestorestate *state, HeapTuple tuple)
#define att_nominal_alignby(cur_offset, attalignby)
static bool att_isnull(int ATT, const bits8 *BITS)
#define att_addlength_pointer(cur_offset, attlen, attptr)
#define att_pointer_alignby(cur_offset, attalignby, attlen, attptr)
static bool VARATT_IS_SHORT(const void *PTR)
static Size VARATT_EXTERNAL_GET_EXTSIZE(struct varatt_external toast_pointer)
static bool VARATT_IS_EXTENDED(const void *PTR)
static bool VARATT_IS_EXTERNAL(const void *PTR)
static Size VARSIZE(const void *PTR)
static vartag_external VARTAG_EXTERNAL(const void *PTR)
static bool VARATT_EXTERNAL_IS_COMPRESSED(struct varatt_external toast_pointer)
static Size VARSIZE_SHORT(const void *PTR)
char * text_to_cstring(const text *t)
TransamVariablesData * TransamVariables
static XidBoundsViolation check_mxid_valid_in_rel(MultiXactId mxid, HeapCheckContext *ctx)
static void check_toasted_attribute(HeapCheckContext *ctx, ToastedAttribute *ta)
#define VARLENA_SIZE_LIMIT
static XidBoundsViolation get_xid_status(TransactionId xid, HeapCheckContext *ctx, XidCommitStatus *status)
@ XID_PRECEDES_CLUSTERMIN
static void report_corruption_internal(Tuplestorestate *tupstore, TupleDesc tupdesc, BlockNumber blkno, OffsetNumber offnum, AttrNumber attnum, char *msg)
static bool check_tuple_visibility(HeapCheckContext *ctx, bool *xmin_commit_status_ok, XidCommitStatus *xmin_commit_status)
#define HEAPCHECK_RELATION_COLS
static void check_toast_tuple(HeapTuple toasttup, HeapCheckContext *ctx, ToastedAttribute *ta, int32 *expected_chunk_seq, uint32 extsize)
static bool fxid_in_cached_range(FullTransactionId fxid, const HeapCheckContext *ctx)
static XidBoundsViolation check_mxid_in_range(MultiXactId mxid, HeapCheckContext *ctx)
static void update_cached_mxid_range(HeapCheckContext *ctx)
static void update_cached_xid_range(HeapCheckContext *ctx)
static FullTransactionId FullTransactionIdFromXidAndCtx(TransactionId xid, const HeapCheckContext *ctx)
static void check_tuple(HeapCheckContext *ctx, bool *xmin_commit_status_ok, XidCommitStatus *xmin_commit_status)
static bool check_tuple_header(HeapCheckContext *ctx)
static void report_toast_corruption(HeapCheckContext *ctx, ToastedAttribute *ta, char *msg)
static bool check_tuple_attribute(HeapCheckContext *ctx)
static void report_corruption(HeapCheckContext *ctx, char *msg)
static BlockNumber heapcheck_read_stream_next_unskippable(ReadStream *stream, void *callback_private_data, void *per_buffer_data)
Datum verify_heapam(PG_FUNCTION_ARGS)
uint8 visibilitymap_get_status(Relation rel, BlockNumber heapBlk, Buffer *vmbuf)
#define VISIBILITYMAP_ALL_FROZEN
#define VISIBILITYMAP_ALL_VISIBLE
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
bool RecoveryInProgress(void)