1/*-------------------------------------------------------------------------
4 * Utility functions common to all access methods.
6 * Copyright (c) 2016-2025, PostgreSQL Global Development Group
9 * contrib/amcheck/verify_common.c
11 *-------------------------------------------------------------------------
31 * Check if index relation should have a file for its main relation fork.
32 * Verification uses this to skip unlogged indexes when in hot standby mode,
33 * where there is simply nothing to verify.
35 * NB: Caller should call index_checkable() before calling here.
40 if (rel->
rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED ||
45 (
errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
46 errmsg(
"cannot verify unlogged index \"%s\" during recovery, skipping",
53* Amcheck main workhorse.
54* Given index relation OID, lock relation.
55* Next, take a number of standard actions:
56* 1) Make sure the index can be checked
57* 2) change the context of the user,
58* 3) keep track of GUCs modified via index functions
59* 4) execute callback function to verify integrity.
76 * We must lock table before index to avoid deadlocks. However, if the
77 * passed indrelid isn't an index then IndexGetRelation() will fail.
78 * Rather than emitting a not-very-helpful error message, postpone
79 * complaining, expecting that the is-it-an-index test below will fail.
81 * In hot standby mode this will raise an error when parentcheck is true.
89 * Switch to the table owner's userid, so that any index functions are
90 * run as that user. Also lock down security-restricted operations
91 * and arrange to make GUC variable changes local to this command.
101 /* Set these just to suppress "uninitialized variable" warnings */
103 save_sec_context = -1;
108 * Open the target index relations separately (like relation_openrv(), but
109 * with heap relation locked first to prevent deadlocking). In hot
110 * standby mode this will raise an error when parentcheck is true.
112 * There is no need for the usual indcheckxmin usability horizon test
113 * here, even in the heapallindexed case, because index undergoing
114 * verification only needs to have entries for a new transaction snapshot.
115 * (If this is a parentcheck verification, there is no question about
116 * committed or recently dead heap tuples lacking index entries due to
117 * concurrent activity.)
122 * Since we did the IndexGetRelation call above without any lock, it's
123 * barely possible that a race against an index drop/recreation could have
124 * netted us the wrong table.
129 errmsg(
"could not open parent table of index \"%s\"",
132 /* Check that relation suitable for checking */
136 /* Roll back any GUC changes executed by index functions */
139 /* Restore userid and security context */
143 * Release locks early. That's ok here because nothing in the called
144 * routines will trigger shared cache invalidations to be sent, so we can
145 * relax the usual pattern of only releasing locks after commit.
153 * Basic checks about the suitability of a relation for checking as an index.
156 * NB: Intentionally not checking permissions, the function is normally not
157 * callable by non-superusers. If granted, it's useful to be able to check a
163 if (rel->
rd_rel->relkind != RELKIND_INDEX)
165 (
errcode(ERRCODE_WRONG_OBJECT_TYPE),
166 errmsg(
"expected index as targets for verification"),
169 if (rel->
rd_rel->relam != am_id)
171 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
173 errdetail(
"Relation \"%s\" is a %s index.",
178 (
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
179 errmsg(
"cannot access temporary tables of other sessions"),
180 errdetail(
"Index \"%s\" is associated with temporary relation.",
185 (
errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
186 errmsg(
"cannot check index \"%s\"",
char * get_am_name(Oid amOid)
#define OidIsValid(objectId)
int errdetail(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
int NewGUCNestLevel(void)
void AtEOXact_GUC(bool isCommit, int nestLevel)
Oid IndexGetRelation(Oid indexId, bool missing_ok)
void index_close(Relation relation, LOCKMODE lockmode)
Relation index_open(Oid relationId, LOCKMODE lockmode)
#define SECURITY_RESTRICTED_OPERATION
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
void SetUserIdAndSecContext(Oid userid, int sec_context)
int errdetail_relkind_not_supported(char relkind)
#define ERRCODE_UNDEFINED_TABLE
#define RelationGetRelationName(relation)
#define RELATION_IS_OTHER_TEMP(relation)
void table_close(Relation relation, LOCKMODE lockmode)
Relation table_open(Oid relationId, LOCKMODE lockmode)
void amcheck_lock_relation_and_check(Oid indrelid, Oid am_id, IndexDoCheckCallback check, LOCKMODE lockmode, void *state)
static bool amcheck_index_mainfork_expected(Relation rel)
static bool index_checkable(Relation rel, Oid am_id)
void(* IndexDoCheckCallback)(Relation rel, Relation heaprel, void *state, bool readonly)
bool RecoveryInProgress(void)