PostgreSQL Source Code: contrib/amcheck/verify_common.c Source File

PostgreSQL Source Code git master
verify_common.c
Go to the documentation of this file.
1/*-------------------------------------------------------------------------
2 *
3 * verify_common.c
4 * Utility functions common to all access methods.
5 *
6 * Copyright (c) 2016-2025, PostgreSQL Global Development Group
7 *
8 * IDENTIFICATION
9 * contrib/amcheck/verify_common.c
10 *
11 *-------------------------------------------------------------------------
12 */
13#include "postgres.h"
14
15#include "access/genam.h"
16#include "access/table.h"
17#include "access/tableam.h"
18#include "verify_common.h"
19#include "catalog/index.h"
20#include "catalog/pg_am.h"
21#include "commands/defrem.h"
22#include "commands/tablecmds.h"
23#include "utils/guc.h"
24#include "utils/syscache.h"
25
26static bool amcheck_index_mainfork_expected(Relation rel);
27static bool index_checkable(Relation rel, Oid am_id);
28
29
30/*
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.
34 *
35 * NB: Caller should call index_checkable() before calling here.
36 */
37static bool
38 amcheck_index_mainfork_expected(Relation rel)
39{
40 if (rel->rd_rel->relpersistence != RELPERSISTENCE_UNLOGGED ||
41 !RecoveryInProgress())
42 return true;
43
44 ereport(NOTICE,
45 (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
46 errmsg("cannot verify unlogged index \"%s\" during recovery, skipping",
47 RelationGetRelationName(rel))));
48
49 return false;
50}
51
52/*
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.
60*/
61void
62 amcheck_lock_relation_and_check(Oid indrelid,
63 Oid am_id,
64 IndexDoCheckCallback check,
65 LOCKMODE lockmode,
66 void *state)
67{
68 Oid heapid;
69 Relation indrel;
70 Relation heaprel;
71 Oid save_userid;
72 int save_sec_context;
73 int save_nestlevel;
74
75 /*
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.
80 *
81 * In hot standby mode this will raise an error when parentcheck is true.
82 */
83 heapid = IndexGetRelation(indrelid, true);
84 if (OidIsValid(heapid))
85 {
86 heaprel = table_open(heapid, lockmode);
87
88 /*
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.
92 */
93 GetUserIdAndSecContext(&save_userid, &save_sec_context);
94 SetUserIdAndSecContext(heaprel->rd_rel->relowner,
95 save_sec_context | SECURITY_RESTRICTED_OPERATION);
96 save_nestlevel = NewGUCNestLevel();
97 }
98 else
99 {
100 heaprel = NULL;
101 /* Set these just to suppress "uninitialized variable" warnings */
102 save_userid = InvalidOid;
103 save_sec_context = -1;
104 save_nestlevel = -1;
105 }
106
107 /*
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.
111 *
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.)
118 */
119 indrel = index_open(indrelid, lockmode);
120
121 /*
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.
125 */
126 if (heaprel == NULL || heapid != IndexGetRelation(indrelid, false))
127 ereport(ERROR,
128 (errcode(ERRCODE_UNDEFINED_TABLE),
129 errmsg("could not open parent table of index \"%s\"",
130 RelationGetRelationName(indrel))));
131
132 /* Check that relation suitable for checking */
133 if (index_checkable(indrel, am_id))
134 check(indrel, heaprel, state, lockmode == ShareLock);
135
136 /* Roll back any GUC changes executed by index functions */
137 AtEOXact_GUC(false, save_nestlevel);
138
139 /* Restore userid and security context */
140 SetUserIdAndSecContext(save_userid, save_sec_context);
141
142 /*
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.
146 */
147 index_close(indrel, lockmode);
148 if (heaprel)
149 table_close(heaprel, lockmode);
150}
151
152/*
153 * Basic checks about the suitability of a relation for checking as an index.
154 *
155 *
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
158 * whole cluster.
159 */
160static bool
161 index_checkable(Relation rel, Oid am_id)
162{
163 if (rel->rd_rel->relkind != RELKIND_INDEX)
164 ereport(ERROR,
165 (errcode(ERRCODE_WRONG_OBJECT_TYPE),
166 errmsg("expected index as targets for verification"),
167 errdetail_relkind_not_supported(rel->rd_rel->relkind)));
168
169 if (rel->rd_rel->relam != am_id)
170 ereport(ERROR,
171 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
172 errmsg("expected \"%s\" index as targets for verification", get_am_name(am_id)),
173 errdetail("Relation \"%s\" is a %s index.",
174 RelationGetRelationName(rel), get_am_name(rel->rd_rel->relam))));
175
176 if (RELATION_IS_OTHER_TEMP(rel))
177 ereport(ERROR,
178 (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
179 errmsg("cannot access temporary tables of other sessions"),
180 errdetail("Index \"%s\" is associated with temporary relation.",
181 RelationGetRelationName(rel))));
182
183 if (!rel->rd_index->indisvalid)
184 ereport(ERROR,
185 (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
186 errmsg("cannot check index \"%s\"",
187 RelationGetRelationName(rel)),
188 errdetail("Index is not valid.")));
189
190 return amcheck_index_mainfork_expected(rel);
191}
char * get_am_name(Oid amOid)
Definition: amcmds.c:192
#define OidIsValid(objectId)
Definition: c.h:774
int errdetail(const char *fmt,...)
Definition: elog.c:1207
int errcode(int sqlerrcode)
Definition: elog.c:854
int errmsg(const char *fmt,...)
Definition: elog.c:1071
#define ERROR
Definition: elog.h:39
#define NOTICE
Definition: elog.h:35
#define ereport(elevel,...)
Definition: elog.h:150
int NewGUCNestLevel(void)
Definition: guc.c:2240
void AtEOXact_GUC(bool isCommit, int nestLevel)
Definition: guc.c:2267
Oid IndexGetRelation(Oid indexId, bool missing_ok)
Definition: index.c:3583
void index_close(Relation relation, LOCKMODE lockmode)
Definition: indexam.c:177
Relation index_open(Oid relationId, LOCKMODE lockmode)
Definition: indexam.c:133
int LOCKMODE
Definition: lockdefs.h:26
#define ShareLock
Definition: lockdefs.h:40
#define SECURITY_RESTRICTED_OPERATION
Definition: miscadmin.h:318
void GetUserIdAndSecContext(Oid *userid, int *sec_context)
Definition: miscinit.c:612
void SetUserIdAndSecContext(Oid userid, int sec_context)
Definition: miscinit.c:619
int errdetail_relkind_not_supported(char relkind)
Definition: pg_class.c:24
#define ERRCODE_UNDEFINED_TABLE
Definition: pgbench.c:79
#define InvalidOid
Definition: postgres_ext.h:37
unsigned int Oid
Definition: postgres_ext.h:32
#define RelationGetRelationName(relation)
Definition: rel.h:548
#define RELATION_IS_OTHER_TEMP(relation)
Definition: rel.h:667
Definition: rel.h:56
Form_pg_index rd_index
Definition: rel.h:192
Form_pg_class rd_rel
Definition: rel.h:111
Definition: regguts.h:323
void table_close(Relation relation, LOCKMODE lockmode)
Definition: table.c:126
Relation table_open(Oid relationId, LOCKMODE lockmode)
Definition: table.c:40
void amcheck_lock_relation_and_check(Oid indrelid, Oid am_id, IndexDoCheckCallback check, LOCKMODE lockmode, void *state)
Definition: verify_common.c:62
static bool amcheck_index_mainfork_expected(Relation rel)
Definition: verify_common.c:38
static bool index_checkable(Relation rel, Oid am_id)
Definition: verify_common.c:161
void(* IndexDoCheckCallback)(Relation rel, Relation heaprel, void *state, bool readonly)
Definition: verify_common.h:20
bool RecoveryInProgress(void)
Definition: xlog.c:6386

AltStyle によって変換されたページ (->オリジナル) /