Coverage Report

Created: 2025-08-12 06:43

/src/postgres/src/backend/access/common/relation.c
Line
Count
Source (jump to first uncovered line)
1
/*-------------------------------------------------------------------------
2
 *
3
 * relation.c
4
 *    Generic relation related routines.
5
 *
6
 * Portions Copyright (c) 1996-2025, PostgreSQL Global Development Group
7
 * Portions Copyright (c) 1994, Regents of the University of California
8
 *
9
 *
10
 * IDENTIFICATION
11
 *    src/backend/access/common/relation.c
12
 *
13
 * NOTES
14
 *    This file contains relation_ routines that implement access to relations
15
 *    (tables, indexes, etc). Support that's specific to subtypes of relations
16
 *    should go into their respective files, not here.
17
 *
18
 *-------------------------------------------------------------------------
19
 */
20
21
#include "postgres.h"
22
23
#include "access/relation.h"
24
#include "access/xact.h"
25
#include "catalog/namespace.h"
26
#include "pgstat.h"
27
#include "storage/lmgr.h"
28
#include "utils/inval.h"
29
#include "utils/syscache.h"
30
31
32
/* ----------------
33
 *    relation_open - open any relation by relation OID
34
 *
35
 *    If lockmode is not "NoLock", the specified kind of lock is
36
 *    obtained on the relation.  (Generally, NoLock should only be
37
 *    used if the caller knows it has some appropriate lock on the
38
 *    relation already.)
39
 *
40
 *    An error is raised if the relation does not exist.
41
 *
42
 *    NB: a "relation" is anything with a pg_class entry.  The caller is
43
 *    expected to check whether the relkind is something it can handle.
44
 * ----------------
45
 */
46
Relation
47
relation_open(Oid relationId, LOCKMODE lockmode)
48
0
{
49
0
  Relation  r;
50
51
0
  Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
52
53
  /* Get the lock before trying to open the relcache entry */
54
0
  if (lockmode != NoLock)
55
0
    LockRelationOid(relationId, lockmode);
56
57
  /* The relcache does all the real work... */
58
0
  r = RelationIdGetRelation(relationId);
59
60
0
  if (!RelationIsValid(r))
61
0
    elog(ERROR, "could not open relation with OID %u", relationId);
62
63
  /*
64
   * If we didn't get the lock ourselves, assert that caller holds one,
65
   * except in bootstrap mode where no locks are used.
66
   */
67
0
  Assert(lockmode != NoLock ||
68
0
       IsBootstrapProcessingMode() ||
69
0
       CheckRelationLockedByMe(r, AccessShareLock, true));
70
71
  /* Make note that we've accessed a temporary relation */
72
0
  if (RelationUsesLocalBuffers(r))
73
0
    MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
74
75
0
  pgstat_init_relation(r);
76
77
0
  return r;
78
0
}
79
80
/* ----------------
81
 *    try_relation_open - open any relation by relation OID
82
 *
83
 *    Same as relation_open, except return NULL instead of failing
84
 *    if the relation does not exist.
85
 * ----------------
86
 */
87
Relation
88
try_relation_open(Oid relationId, LOCKMODE lockmode)
89
0
{
90
0
  Relation  r;
91
92
0
  Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
93
94
  /* Get the lock first */
95
0
  if (lockmode != NoLock)
96
0
    LockRelationOid(relationId, lockmode);
97
98
  /*
99
   * Now that we have the lock, probe to see if the relation really exists
100
   * or not.
101
   */
102
0
  if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(relationId)))
103
0
  {
104
    /* Release useless lock */
105
0
    if (lockmode != NoLock)
106
0
      UnlockRelationOid(relationId, lockmode);
107
108
0
    return NULL;
109
0
  }
110
111
  /* Should be safe to do a relcache load */
112
0
  r = RelationIdGetRelation(relationId);
113
114
0
  if (!RelationIsValid(r))
115
0
    elog(ERROR, "could not open relation with OID %u", relationId);
116
117
  /* If we didn't get the lock ourselves, assert that caller holds one */
118
0
  Assert(lockmode != NoLock ||
119
0
       CheckRelationLockedByMe(r, AccessShareLock, true));
120
121
  /* Make note that we've accessed a temporary relation */
122
0
  if (RelationUsesLocalBuffers(r))
123
0
    MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
124
125
0
  pgstat_init_relation(r);
126
127
0
  return r;
128
0
}
129
130
/* ----------------
131
 *    relation_openrv - open any relation specified by a RangeVar
132
 *
133
 *    Same as relation_open, but the relation is specified by a RangeVar.
134
 * ----------------
135
 */
136
Relation
137
relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
138
0
{
139
0
  Oid     relOid;
140
141
  /*
142
   * Check for shared-cache-inval messages before trying to open the
143
   * relation.  This is needed even if we already hold a lock on the
144
   * relation, because GRANT/REVOKE are executed without taking any lock on
145
   * the target relation, and we want to be sure we see current ACL
146
   * information.  We can skip this if asked for NoLock, on the assumption
147
   * that such a call is not the first one in the current command, and so we
148
   * should be reasonably up-to-date already.  (XXX this all could stand to
149
   * be redesigned, but for the moment we'll keep doing this like it's been
150
   * done historically.)
151
   */
152
0
  if (lockmode != NoLock)
153
0
    AcceptInvalidationMessages();
154
155
  /* Look up and lock the appropriate relation using namespace search */
156
0
  relOid = RangeVarGetRelid(relation, lockmode, false);
157
158
  /* Let relation_open do the rest */
159
0
  return relation_open(relOid, NoLock);
160
0
}
161
162
/* ----------------
163
 *    relation_openrv_extended - open any relation specified by a RangeVar
164
 *
165
 *    Same as relation_openrv, but with an additional missing_ok argument
166
 *    allowing a NULL return rather than an error if the relation is not
167
 *    found.  (Note that some other causes, such as permissions problems,
168
 *    will still result in an ereport.)
169
 * ----------------
170
 */
171
Relation
172
relation_openrv_extended(const RangeVar *relation, LOCKMODE lockmode,
173
             bool missing_ok)
174
0
{
175
0
  Oid     relOid;
176
177
  /*
178
   * Check for shared-cache-inval messages before trying to open the
179
   * relation.  See comments in relation_openrv().
180
   */
181
0
  if (lockmode != NoLock)
182
0
    AcceptInvalidationMessages();
183
184
  /* Look up and lock the appropriate relation using namespace search */
185
0
  relOid = RangeVarGetRelid(relation, lockmode, missing_ok);
186
187
  /* Return NULL on not-found */
188
0
  if (!OidIsValid(relOid))
189
0
    return NULL;
190
191
  /* Let relation_open do the rest */
192
0
  return relation_open(relOid, NoLock);
193
0
}
194
195
/* ----------------
196
 *    relation_close - close any relation
197
 *
198
 *    If lockmode is not "NoLock", we then release the specified lock.
199
 *
200
 *    Note that it is often sensible to hold a lock beyond relation_close;
201
 *    in that case, the lock is released automatically at xact end.
202
 * ----------------
203
 */
204
void
205
relation_close(Relation relation, LOCKMODE lockmode)
206
0
{
207
0
  LockRelId relid = relation->rd_lockInfo.lockRelId;
208
209
0
  Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
210
211
  /* The relcache does the real work... */
212
0
  RelationClose(relation);
213
214
0
  if (lockmode != NoLock)
215
0
    UnlockRelationId(&relid, lockmode);
216
0
}