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