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
48 52571948 : relation_open(Oid relationId, LOCKMODE lockmode)
49 : {
50 : Relation r;
51 :
52 : Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
53 :
54 : /* Get the lock before trying to open the relcache entry */
55 52571948 : if (lockmode != NoLock)
56 48733666 : LockRelationOid(relationId, lockmode);
57 :
58 : /* The relcache does all the real work... */
59 52571946 : r = RelationIdGetRelation(relationId);
60 :
61 52571926 : if (!RelationIsValid(r))
62 14 : 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 : Assert(lockmode != NoLock ||
69 : IsBootstrapProcessingMode() ||
70 : CheckRelationLockedByMe(r, AccessShareLock, true));
71 :
72 : /* Make note that we've accessed a temporary relation */
73 52571912 : if (RelationUsesLocalBuffers(r))
74 245110 : MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
75 :
76 52571912 : pgstat_init_relation(r);
77 :
78 52571912 : 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 423690 : try_relation_open(Oid relationId, LOCKMODE lockmode)
90 : {
91 : Relation r;
92 :
93 : Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
94 :
95 : /* Get the lock first */
96 423690 : if (lockmode != NoLock)
97 422758 : 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 423690 : if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(relationId)))
104 : {
105 : /* Release useless lock */
106 14 : if (lockmode != NoLock)
107 14 : UnlockRelationOid(relationId, lockmode);
108 :
109 14 : return NULL;
110 : }
111 :
112 : /* Should be safe to do a relcache load */
113 423676 : r = RelationIdGetRelation(relationId);
114 :
115 423676 : if (!RelationIsValid(r))
116 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 */
119 : Assert(lockmode != NoLock ||
120 : CheckRelationLockedByMe(r, AccessShareLock, true));
121 :
122 : /* Make note that we've accessed a temporary relation */
123 423676 : if (RelationUsesLocalBuffers(r))
124 496 : MyXactFlags |= XACT_FLAGS_ACCESSEDTEMPNAMESPACE;
125 :
126 423676 : pgstat_init_relation(r);
127 :
128 423676 : 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 81100 : 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 81100 : if (lockmode != NoLock)
154 44582 : AcceptInvalidationMessages();
155 :
156 : /* Look up and lock the appropriate relation using namespace search */
157 81100 : relOid = RangeVarGetRelid(relation, lockmode, false);
158 :
159 : /* Let relation_open do the rest */
160 81000 : 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 649906 : 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 649906 : if (lockmode != NoLock)
183 649906 : AcceptInvalidationMessages();
184 :
185 : /* Look up and lock the appropriate relation using namespace search */
186 649906 : relOid = RangeVarGetRelid(relation, lockmode, missing_ok);
187 :
188 : /* Return NULL on not-found */
189 649512 : if (!OidIsValid(relOid))
190 218 : return NULL;
191 :
192 : /* Let relation_open do the rest */
193 649294 : 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 28183032 : relation_close(Relation relation, LOCKMODE lockmode)
207 : {
208 28183032 : LockRelId relid = relation->rd_lockInfo.lockRelId;
209 :
210 : Assert(lockmode >= NoLock && lockmode < MAX_LOCKMODES);
211 :
212 : /* The relcache does the real work... */
213 28183032 : RelationClose(relation);
214 :
215 28183032 : if (lockmode != NoLock)
216 22159022 : UnlockRelationId(&relid, lockmode);
217 28183032 : }
|