Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * relation.c
4 : * Generic relation related routines.
5 : *
6 : * Portions Copyright (c) 1996-2024, 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 34995386 : relation_open(Oid relationId, LOCKMODE lockmode)
48 : {
49 : Relation r;
50 :
51 : Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
52 :
53 : /* Get the lock before trying to open the relcache entry */
54 34995386 : if (lockmode != NoLock)
55 31492494 : LockRelationOid(relationId, lockmode);
56 :
57 : /* The relcache does all the real work... */
58 34995374 : r = RelationIdGetRelation(relationId);
59 :
60 34995360 : if (!RelationIsValid(r))
61 50 : 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 : Assert(lockmode != NoLock ||
68 : IsBootstrapProcessingMode() ||
69 : CheckRelationLockedByMe(r, AccessShareLock, true));
70 :
71 : /* Make note that we've accessed a temporary relation */
72 34995310 : if (RelationUsesLocalBuffers(r))
73 253158 : MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
74 :
75 34995310 : pgstat_init_relation(r);
76 :
77 34995310 : return r;
78 : }
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 456720 : try_relation_open(Oid relationId, LOCKMODE lockmode)
89 : {
90 : Relation r;
91 :
92 : Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
93 :
94 : /* Get the lock first */
95 456720 : if (lockmode != NoLock)
96 456018 : 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 456720 : if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(relationId)))
103 : {
104 : /* Release useless lock */
105 14 : if (lockmode != NoLock)
106 14 : UnlockRelationOid(relationId, lockmode);
107 :
108 14 : return NULL;
109 : }
110 :
111 : /* Should be safe to do a relcache load */
112 456706 : r = RelationIdGetRelation(relationId);
113 :
114 456706 : 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 : Assert(lockmode != NoLock ||
119 : CheckRelationLockedByMe(r, AccessShareLock, true));
120 :
121 : /* Make note that we've accessed a temporary relation */
122 456706 : if (RelationUsesLocalBuffers(r))
123 878 : MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
124 :
125 456706 : pgstat_init_relation(r);
126 :
127 456706 : return r;
128 : }
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 32626 : relation_openrv(const RangeVar *relation, LOCKMODE lockmode)
138 : {
139 : 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 32626 : if (lockmode != NoLock)
153 27044 : AcceptInvalidationMessages();
154 :
155 : /* Look up and lock the appropriate relation using namespace search */
156 32626 : relOid = RangeVarGetRelid(relation, lockmode, false);
157 :
158 : /* Let relation_open do the rest */
159 32526 : return relation_open(relOid, NoLock);
160 : }
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 447420 : relation_openrv_extended(const RangeVar *relation, LOCKMODE lockmode,
173 : bool missing_ok)
174 : {
175 : 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 447420 : if (lockmode != NoLock)
182 447420 : AcceptInvalidationMessages();
183 :
184 : /* Look up and lock the appropriate relation using namespace search */
185 447420 : relOid = RangeVarGetRelid(relation, lockmode, missing_ok);
186 :
187 : /* Return NULL on not-found */
188 447026 : if (!OidIsValid(relOid))
189 228 : return NULL;
190 :
191 : /* Let relation_open do the rest */
192 446798 : return relation_open(relOid, NoLock);
193 : }
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 18517946 : relation_close(Relation relation, LOCKMODE lockmode)
206 : {
207 18517946 : LockRelId relid = relation->rd_lockInfo.lockRelId;
208 :
209 : Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
210 :
211 : /* The relcache does the real work... */
212 18517946 : RelationClose(relation);
213 :
214 18517946 : if (lockmode != NoLock)
215 14079392 : UnlockRelationId(&relid, lockmode);
216 18517946 : }
|