Line data Source code
1 : /*-------------------------------------------------------------------------
2 : *
3 : * relcache.c
4 : * POSTGRES relation descriptor cache code
5 : *
6 : * Portions Copyright (c) 1996-2026, PostgreSQL Global Development Group
7 : * Portions Copyright (c) 1994, Regents of the University of California
8 : *
9 : *
10 : * IDENTIFICATION
11 : * src/backend/utils/cache/relcache.c
12 : *
13 : *-------------------------------------------------------------------------
14 : */
15 : /*
16 : * INTERFACE ROUTINES
17 : * RelationCacheInitialize - initialize relcache (to empty)
18 : * RelationCacheInitializePhase2 - initialize shared-catalog entries
19 : * RelationCacheInitializePhase3 - finish initializing relcache
20 : * RelationIdGetRelation - get a reldesc by relation id
21 : * RelationClose - close an open relation
22 : *
23 : * NOTES
24 : * The following code contains many undocumented hacks. Please be
25 : * careful....
26 : */
27 : #include "postgres.h"
28 :
29 : #include <sys/file.h>
30 : #include <fcntl.h>
31 : #include <unistd.h>
32 :
33 : #include "access/htup_details.h"
34 : #include "access/multixact.h"
35 : #include "access/parallel.h"
36 : #include "access/reloptions.h"
37 : #include "access/sysattr.h"
38 : #include "access/table.h"
39 : #include "access/tableam.h"
40 : #include "access/tupdesc_details.h"
41 : #include "access/xact.h"
42 : #include "catalog/binary_upgrade.h"
43 : #include "catalog/catalog.h"
44 : #include "catalog/indexing.h"
45 : #include "catalog/namespace.h"
46 : #include "catalog/partition.h"
47 : #include "catalog/pg_am.h"
48 : #include "catalog/pg_amproc.h"
49 : #include "catalog/pg_attrdef.h"
50 : #include "catalog/pg_auth_members.h"
51 : #include "catalog/pg_authid.h"
52 : #include "catalog/pg_constraint.h"
53 : #include "catalog/pg_database.h"
54 : #include "catalog/pg_namespace.h"
55 : #include "catalog/pg_opclass.h"
56 : #include "catalog/pg_proc.h"
57 : #include "catalog/pg_publication.h"
58 : #include "catalog/pg_rewrite.h"
59 : #include "catalog/pg_shseclabel.h"
60 : #include "catalog/pg_statistic_ext.h"
61 : #include "catalog/pg_subscription.h"
62 : #include "catalog/pg_tablespace.h"
63 : #include "catalog/pg_trigger.h"
64 : #include "catalog/pg_type.h"
65 : #include "catalog/schemapg.h"
66 : #include "catalog/storage.h"
67 : #include "commands/policy.h"
68 : #include "commands/publicationcmds.h"
69 : #include "commands/trigger.h"
70 : #include "common/int.h"
71 : #include "miscadmin.h"
72 : #include "nodes/makefuncs.h"
73 : #include "nodes/nodeFuncs.h"
74 : #include "optimizer/optimizer.h"
75 : #include "pgstat.h"
76 : #include "rewrite/rewriteDefine.h"
77 : #include "rewrite/rowsecurity.h"
78 : #include "storage/fd.h"
79 : #include "storage/lmgr.h"
80 : #include "storage/lock.h"
81 : #include "storage/smgr.h"
82 : #include "utils/array.h"
83 : #include "utils/builtins.h"
84 : #include "utils/catcache.h"
85 : #include "utils/datum.h"
86 : #include "utils/fmgroids.h"
87 : #include "utils/inval.h"
88 : #include "utils/lsyscache.h"
89 : #include "utils/memutils.h"
90 : #include "utils/relmapper.h"
91 : #include "utils/resowner.h"
92 : #include "utils/snapmgr.h"
93 : #include "utils/syscache.h"
94 :
95 : #define RELCACHE_INIT_FILEMAGIC 0x573266 /* version ID value */
96 :
97 : /*
98 : * Whether to bother checking if relation cache memory needs to be freed
99 : * eagerly. See also RelationBuildDesc() and pg_config_manual.h.
100 : */
101 : #if defined(RECOVER_RELATION_BUILD_MEMORY) && (RECOVER_RELATION_BUILD_MEMORY != 0)
102 : #define MAYBE_RECOVER_RELATION_BUILD_MEMORY 1
103 : #else
104 : #define RECOVER_RELATION_BUILD_MEMORY 0
105 : #ifdef DISCARD_CACHES_ENABLED
106 : #define MAYBE_RECOVER_RELATION_BUILD_MEMORY 1
107 : #endif
108 : #endif
109 :
110 : /*
111 : * hardcoded tuple descriptors, contents generated by genbki.pl
112 : */
113 : static const FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class};
114 : static const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = {Schema_pg_attribute};
115 : static const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc] = {Schema_pg_proc};
116 : static const FormData_pg_attribute Desc_pg_type[Natts_pg_type] = {Schema_pg_type};
117 : static const FormData_pg_attribute Desc_pg_database[Natts_pg_database] = {Schema_pg_database};
118 : static const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid] = {Schema_pg_authid};
119 : static const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members] = {Schema_pg_auth_members};
120 : static const FormData_pg_attribute Desc_pg_index[Natts_pg_index] = {Schema_pg_index};
121 : static const FormData_pg_attribute Desc_pg_shseclabel[Natts_pg_shseclabel] = {Schema_pg_shseclabel};
122 : static const FormData_pg_attribute Desc_pg_subscription[Natts_pg_subscription] = {Schema_pg_subscription};
123 :
124 : /*
125 : * Hash tables that index the relation cache
126 : *
127 : * We used to index the cache by both name and OID, but now there
128 : * is only an index by OID.
129 : */
130 : typedef struct relidcacheent
131 : {
132 : Oid reloid;
133 : Relation reldesc;
134 : } RelIdCacheEnt;
135 :
136 : static HTAB *RelationIdCache;
137 :
138 : /*
139 : * This flag is false until we have prepared the critical relcache entries
140 : * that are needed to do indexscans on the tables read by relcache building.
141 : */
142 : bool criticalRelcachesBuilt = false;
143 :
144 : /*
145 : * This flag is false until we have prepared the critical relcache entries
146 : * for shared catalogs (which are the tables needed for login).
147 : */
148 : bool criticalSharedRelcachesBuilt = false;
149 :
150 : /*
151 : * This counter counts relcache inval events received since backend startup
152 : * (but only for rels that are actually in cache). Presently, we use it only
153 : * to detect whether data about to be written by write_relcache_init_file()
154 : * might already be obsolete.
155 : */
156 : static long relcacheInvalsReceived = 0L;
157 :
158 : /*
159 : * in_progress_list is a stack of ongoing RelationBuildDesc() calls. CREATE
160 : * INDEX CONCURRENTLY makes catalog changes under ShareUpdateExclusiveLock.
161 : * It critically relies on each backend absorbing those changes no later than
162 : * next transaction start. Hence, RelationBuildDesc() loops until it finishes
163 : * without accepting a relevant invalidation. (Most invalidation consumers
164 : * don't do this.)
165 : */
166 : typedef struct inprogressent
167 : {
168 : Oid reloid; /* OID of relation being built */
169 : bool invalidated; /* whether an invalidation arrived for it */
170 : } InProgressEnt;
171 :
172 : static InProgressEnt *in_progress_list;
173 : static int in_progress_list_len;
174 : static int in_progress_list_maxlen;
175 :
176 : /*
177 : * eoxact_list[] stores the OIDs of relations that (might) need AtEOXact
178 : * cleanup work. This list intentionally has limited size; if it overflows,
179 : * we fall back to scanning the whole hashtable. There is no value in a very
180 : * large list because (1) at some point, a hash_seq_search scan is faster than
181 : * retail lookups, and (2) the value of this is to reduce EOXact work for
182 : * short transactions, which can't have dirtied all that many tables anyway.
183 : * EOXactListAdd() does not bother to prevent duplicate list entries, so the
184 : * cleanup processing must be idempotent.
185 : */
186 : #define MAX_EOXACT_LIST 32
187 : static Oid eoxact_list[MAX_EOXACT_LIST];
188 : static int eoxact_list_len = 0;
189 : static bool eoxact_list_overflowed = false;
190 :
191 : #define EOXactListAdd(rel) \
192 : do { \
193 : if (eoxact_list_len < MAX_EOXACT_LIST) \
194 : eoxact_list[eoxact_list_len++] = (rel)->rd_id; \
195 : else \
196 : eoxact_list_overflowed = true; \
197 : } while (0)
198 :
199 : /*
200 : * EOXactTupleDescArray stores TupleDescs that (might) need AtEOXact
201 : * cleanup work. The array expands as needed; there is no hashtable because
202 : * we don't need to access individual items except at EOXact.
203 : */
204 : static TupleDesc *EOXactTupleDescArray;
205 : static int NextEOXactTupleDescNum = 0;
206 : static int EOXactTupleDescArrayLen = 0;
207 :
208 : /*
209 : * macros to manipulate the lookup hashtable
210 : */
211 : #define RelationCacheInsert(RELATION, replace_allowed) \
212 : do { \
213 : RelIdCacheEnt *hentry; bool found; \
214 : hentry = (RelIdCacheEnt *) hash_search(RelationIdCache, \
215 : &((RELATION)->rd_id), \
216 : HASH_ENTER, &found); \
217 : if (found) \
218 : { \
219 : /* see comments in RelationBuildDesc and RelationBuildLocalRelation */ \
220 : Relation _old_rel = hentry->reldesc; \
221 : Assert(replace_allowed); \
222 : hentry->reldesc = (RELATION); \
223 : if (RelationHasReferenceCountZero(_old_rel)) \
224 : RelationDestroyRelation(_old_rel, false); \
225 : else if (!IsBootstrapProcessingMode()) \
226 : elog(WARNING, "leaking still-referenced relcache entry for \"%s\"", \
227 : RelationGetRelationName(_old_rel)); \
228 : } \
229 : else \
230 : hentry->reldesc = (RELATION); \
231 : } while(0)
232 :
233 : #define RelationIdCacheLookup(ID, RELATION) \
234 : do { \
235 : RelIdCacheEnt *hentry; \
236 : hentry = (RelIdCacheEnt *) hash_search(RelationIdCache, \
237 : &(ID), \
238 : HASH_FIND, NULL); \
239 : if (hentry) \
240 : RELATION = hentry->reldesc; \
241 : else \
242 : RELATION = NULL; \
243 : } while(0)
244 :
245 : #define RelationCacheDelete(RELATION) \
246 : do { \
247 : RelIdCacheEnt *hentry; \
248 : hentry = (RelIdCacheEnt *) hash_search(RelationIdCache, \
249 : &((RELATION)->rd_id), \
250 : HASH_REMOVE, NULL); \
251 : if (hentry == NULL) \
252 : elog(WARNING, "failed to delete relcache entry for OID %u", \
253 : (RELATION)->rd_id); \
254 : } while(0)
255 :
256 :
257 : /*
258 : * Special cache for opclass-related information
259 : *
260 : * Note: only default support procs get cached, ie, those with
261 : * lefttype = righttype = opcintype.
262 : */
263 : typedef struct opclasscacheent
264 : {
265 : Oid opclassoid; /* lookup key: OID of opclass */
266 : bool valid; /* set true after successful fill-in */
267 : StrategyNumber numSupport; /* max # of support procs (from pg_am) */
268 : Oid opcfamily; /* OID of opclass's family */
269 : Oid opcintype; /* OID of opclass's declared input type */
270 : RegProcedure *supportProcs; /* OIDs of support procedures */
271 : } OpClassCacheEnt;
272 :
273 : static HTAB *OpClassCache = NULL;
274 :
275 :
276 : /* non-export function prototypes */
277 :
278 : static void RelationCloseCleanup(Relation relation);
279 : static void RelationDestroyRelation(Relation relation, bool remember_tupdesc);
280 : static void RelationInvalidateRelation(Relation relation);
281 : static void RelationClearRelation(Relation relation);
282 : static void RelationRebuildRelation(Relation relation);
283 :
284 : static void RelationReloadIndexInfo(Relation relation);
285 : static void RelationReloadNailed(Relation relation);
286 : static void RelationFlushRelation(Relation relation);
287 : static void RememberToFreeTupleDescAtEOX(TupleDesc td);
288 : #ifdef USE_ASSERT_CHECKING
289 : static void AssertPendingSyncConsistency(Relation relation);
290 : #endif
291 : static void AtEOXact_cleanup(Relation relation, bool isCommit);
292 : static void AtEOSubXact_cleanup(Relation relation, bool isCommit,
293 : SubTransactionId mySubid, SubTransactionId parentSubid);
294 : static bool load_relcache_init_file(bool shared);
295 : static void write_relcache_init_file(bool shared);
296 : static void write_item(const void *data, Size len, FILE *fp);
297 :
298 : static void formrdesc(const char *relationName, Oid relationReltype,
299 : bool isshared, int natts, const FormData_pg_attribute *attrs);
300 :
301 : static HeapTuple ScanPgRelation(Oid targetRelId, bool indexOK, bool force_non_historic);
302 : static Relation AllocateRelationDesc(Form_pg_class relp);
303 : static void RelationParseRelOptions(Relation relation, HeapTuple tuple);
304 : static void RelationBuildTupleDesc(Relation relation);
305 : static Relation RelationBuildDesc(Oid targetRelId, bool insertIt);
306 : static void RelationInitPhysicalAddr(Relation relation);
307 : static void load_critical_index(Oid indexoid, Oid heapoid);
308 : static TupleDesc GetPgClassDescriptor(void);
309 : static TupleDesc GetPgIndexDescriptor(void);
310 : static void AttrDefaultFetch(Relation relation, int ndef);
311 : static int AttrDefaultCmp(const void *a, const void *b);
312 : static void CheckNNConstraintFetch(Relation relation);
313 : static int CheckConstraintCmp(const void *a, const void *b);
314 : static void InitIndexAmRoutine(Relation relation);
315 : static void IndexSupportInitialize(oidvector *indclass,
316 : RegProcedure *indexSupport,
317 : Oid *opFamily,
318 : Oid *opcInType,
319 : StrategyNumber maxSupportNumber,
320 : AttrNumber maxAttributeNumber);
321 : static OpClassCacheEnt *LookupOpclassInfo(Oid operatorClassOid,
322 : StrategyNumber numSupport);
323 : static void RelationCacheInitFileRemoveInDir(const char *tblspcpath);
324 : static void unlink_initfile(const char *initfilename, int elevel);
325 :
326 :
327 : /*
328 : * ScanPgRelation
329 : *
330 : * This is used by RelationBuildDesc to find a pg_class
331 : * tuple matching targetRelId. The caller must hold at least
332 : * AccessShareLock on the target relid to prevent concurrent-update
333 : * scenarios; it isn't guaranteed that all scans used to build the
334 : * relcache entry will use the same snapshot. If, for example,
335 : * an attribute were to be added after scanning pg_class and before
336 : * scanning pg_attribute, relnatts wouldn't match.
337 : *
338 : * NB: the returned tuple has been copied into palloc'd storage
339 : * and must eventually be freed with heap_freetuple.
340 : */
341 : static HeapTuple
342 1170946 : ScanPgRelation(Oid targetRelId, bool indexOK, bool force_non_historic)
343 : {
344 : HeapTuple pg_class_tuple;
345 : Relation pg_class_desc;
346 : SysScanDesc pg_class_scan;
347 : ScanKeyData key[1];
348 1170946 : Snapshot snapshot = NULL;
349 :
350 : /*
351 : * If something goes wrong during backend startup, we might find ourselves
352 : * trying to read pg_class before we've selected a database. That ain't
353 : * gonna work, so bail out with a useful error message. If this happens,
354 : * it probably means a relcache entry that needs to be nailed isn't.
355 : */
356 1170946 : if (!OidIsValid(MyDatabaseId))
357 0 : elog(FATAL, "cannot read pg_class without having selected a database");
358 :
359 : /*
360 : * form a scan key
361 : */
362 1170946 : ScanKeyInit(&key[0],
363 : Anum_pg_class_oid,
364 : BTEqualStrategyNumber, F_OIDEQ,
365 : ObjectIdGetDatum(targetRelId));
366 :
367 : /*
368 : * Open pg_class and fetch a tuple. Force heap scan if we haven't yet
369 : * built the critical relcache entries (this includes initdb and startup
370 : * without a pg_internal.init file). The caller can also force a heap
371 : * scan by setting indexOK == false.
372 : */
373 1170946 : pg_class_desc = table_open(RelationRelationId, AccessShareLock);
374 :
375 : /*
376 : * The caller might need a tuple that's newer than what's visible to the
377 : * historic snapshot; currently the only case requiring to do so is
378 : * looking up the relfilenumber of non mapped system relations during
379 : * decoding.
380 : */
381 1170946 : if (force_non_historic)
382 1884 : snapshot = RegisterSnapshot(GetNonHistoricCatalogSnapshot(RelationRelationId));
383 :
384 1170946 : pg_class_scan = systable_beginscan(pg_class_desc, ClassOidIndexId,
385 1170946 : indexOK && criticalRelcachesBuilt,
386 : snapshot,
387 1170946 : 1, key);
388 :
389 1170943 : pg_class_tuple = systable_getnext(pg_class_scan);
390 :
391 : /*
392 : * Must copy tuple before releasing buffer.
393 : */
394 1170940 : if (HeapTupleIsValid(pg_class_tuple))
395 1170934 : pg_class_tuple = heap_copytuple(pg_class_tuple);
396 :
397 : /* all done */
398 1170940 : systable_endscan(pg_class_scan);
399 :
400 1170940 : if (snapshot)
401 1884 : UnregisterSnapshot(snapshot);
402 :
403 1170940 : table_close(pg_class_desc, AccessShareLock);
404 :
405 1170940 : return pg_class_tuple;
406 : }
407 :
408 : /*
409 : * AllocateRelationDesc
410 : *
411 : * This is used to allocate memory for a new relation descriptor
412 : * and initialize the rd_rel field from the given pg_class tuple.
413 : */
414 : static Relation
415 1073632 : AllocateRelationDesc(Form_pg_class relp)
416 : {
417 : Relation relation;
418 : MemoryContext oldcxt;
419 : Form_pg_class relationForm;
420 :
421 : /* Relcache entries must live in CacheMemoryContext */
422 1073632 : oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
423 :
424 : /*
425 : * allocate and zero space for new relation descriptor
426 : */
427 1073632 : relation = palloc0_object(RelationData);
428 :
429 : /* make sure relation is marked as having no open file yet */
430 1073632 : relation->rd_smgr = NULL;
431 :
432 : /*
433 : * Copy the relation tuple form
434 : *
435 : * We only allocate space for the fixed fields, ie, CLASS_TUPLE_SIZE. The
436 : * variable-length fields (relacl, reloptions) are NOT stored in the
437 : * relcache --- there'd be little point in it, since we don't copy the
438 : * tuple's nulls bitmap and hence wouldn't know if the values are valid.
439 : * Bottom line is that relacl *cannot* be retrieved from the relcache. Get
440 : * it from the syscache if you need it. The same goes for the original
441 : * form of reloptions (however, we do store the parsed form of reloptions
442 : * in rd_options).
443 : */
444 1073632 : relationForm = (Form_pg_class) palloc(CLASS_TUPLE_SIZE);
445 :
446 1073632 : memcpy(relationForm, relp, CLASS_TUPLE_SIZE);
447 :
448 : /* initialize relation tuple form */
449 1073632 : relation->rd_rel = relationForm;
450 :
451 : /* and allocate attribute tuple form storage */
452 1073632 : relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts);
453 : /* which we mark as a reference-counted tupdesc */
454 1073632 : relation->rd_att->tdrefcount = 1;
455 :
456 1073632 : MemoryContextSwitchTo(oldcxt);
457 :
458 1073632 : return relation;
459 : }
460 :
461 : /*
462 : * RelationParseRelOptions
463 : * Convert pg_class.reloptions into pre-parsed rd_options
464 : *
465 : * tuple is the real pg_class tuple (not rd_rel!) for relation
466 : *
467 : * Note: rd_rel and (if an index) rd_indam must be valid already
468 : */
469 : static void
470 1163814 : RelationParseRelOptions(Relation relation, HeapTuple tuple)
471 : {
472 : bytea *options;
473 : amoptions_function amoptsfn;
474 :
475 1163814 : relation->rd_options = NULL;
476 :
477 : /*
478 : * Look up any AM-specific parse function; fall out if relkind should not
479 : * have options.
480 : */
481 1163814 : switch (relation->rd_rel->relkind)
482 : {
483 643704 : case RELKIND_RELATION:
484 : case RELKIND_TOASTVALUE:
485 : case RELKIND_VIEW:
486 : case RELKIND_MATVIEW:
487 : case RELKIND_PARTITIONED_TABLE:
488 643704 : amoptsfn = NULL;
489 643704 : break;
490 509192 : case RELKIND_INDEX:
491 : case RELKIND_PARTITIONED_INDEX:
492 509192 : amoptsfn = relation->rd_indam->amoptions;
493 509192 : break;
494 10918 : default:
495 10918 : return;
496 : }
497 :
498 : /*
499 : * Fetch reloptions from tuple; have to use a hardwired descriptor because
500 : * we might not have any other for pg_class yet (consider executing this
501 : * code for pg_class itself)
502 : */
503 1152896 : options = extractRelOptions(tuple, GetPgClassDescriptor(), amoptsfn);
504 :
505 : /*
506 : * Copy parsed data into CacheMemoryContext. To guard against the
507 : * possibility of leaks in the reloptions code, we want to do the actual
508 : * parsing in the caller's memory context and copy the results into
509 : * CacheMemoryContext after the fact.
510 : */
511 1152896 : if (options)
512 : {
513 12852 : relation->rd_options = MemoryContextAlloc(CacheMemoryContext,
514 : VARSIZE(options));
515 12852 : memcpy(relation->rd_options, options, VARSIZE(options));
516 12852 : pfree(options);
517 : }
518 : }
519 :
520 : /*
521 : * RelationBuildTupleDesc
522 : *
523 : * Form the relation's tuple descriptor from information in
524 : * the pg_attribute, pg_attrdef & pg_constraint system catalogs.
525 : */
526 : static void
527 1073632 : RelationBuildTupleDesc(Relation relation)
528 : {
529 : HeapTuple pg_attribute_tuple;
530 : Relation pg_attribute_desc;
531 : SysScanDesc pg_attribute_scan;
532 : ScanKeyData skey[2];
533 : int need;
534 : TupleConstr *constr;
535 1073632 : AttrMissing *attrmiss = NULL;
536 1073632 : int ndef = 0;
537 :
538 : /* fill rd_att's type ID fields (compare heap.c's AddNewRelationTuple) */
539 1073632 : relation->rd_att->tdtypeid =
540 1073632 : relation->rd_rel->reltype ? relation->rd_rel->reltype : RECORDOID;
541 1073632 : relation->rd_att->tdtypmod = -1; /* just to be sure */
542 :
543 1073632 : constr = (TupleConstr *) MemoryContextAllocZero(CacheMemoryContext,
544 : sizeof(TupleConstr));
545 :
546 : /*
547 : * Form a scan key that selects only user attributes (attnum > 0).
548 : * (Eliminating system attribute rows at the index level is lots faster
549 : * than fetching them.)
550 : */
551 1073632 : ScanKeyInit(&skey[0],
552 : Anum_pg_attribute_attrelid,
553 : BTEqualStrategyNumber, F_OIDEQ,
554 : ObjectIdGetDatum(RelationGetRelid(relation)));
555 1073632 : ScanKeyInit(&skey[1],
556 : Anum_pg_attribute_attnum,
557 : BTGreaterStrategyNumber, F_INT2GT,
558 : Int16GetDatum(0));
559 :
560 : /*
561 : * Open pg_attribute and begin a scan. Force heap scan if we haven't yet
562 : * built the critical relcache entries (this includes initdb and startup
563 : * without a pg_internal.init file).
564 : */
565 1073632 : pg_attribute_desc = table_open(AttributeRelationId, AccessShareLock);
566 1073632 : pg_attribute_scan = systable_beginscan(pg_attribute_desc,
567 : AttributeRelidNumIndexId,
568 : criticalRelcachesBuilt,
569 : NULL,
570 : 2, skey);
571 :
572 : /*
573 : * add attribute data to relation->rd_att
574 : */
575 1073632 : need = RelationGetNumberOfAttributes(relation);
576 :
577 3713284 : while (HeapTupleIsValid(pg_attribute_tuple = systable_getnext(pg_attribute_scan)))
578 : {
579 : Form_pg_attribute attp;
580 : int attnum;
581 :
582 3707831 : attp = (Form_pg_attribute) GETSTRUCT(pg_attribute_tuple);
583 :
584 3707831 : attnum = attp->attnum;
585 3707831 : if (attnum <= 0 || attnum > RelationGetNumberOfAttributes(relation))
586 0 : elog(ERROR, "invalid attribute number %d for relation \"%s\"",
587 : attp->attnum, RelationGetRelationName(relation));
588 :
589 3707831 : memcpy(TupleDescAttr(relation->rd_att, attnum - 1),
590 : attp,
591 : ATTRIBUTE_FIXED_PART_SIZE);
592 :
593 3707831 : populate_compact_attribute(relation->rd_att, attnum - 1);
594 :
595 : /* Update constraint/default info */
596 3707831 : if (attp->attnotnull)
597 1530140 : constr->has_not_null = true;
598 3707831 : if (attp->attgenerated == ATTRIBUTE_GENERATED_STORED)
599 8419 : constr->has_generated_stored = true;
600 3707831 : if (attp->attgenerated == ATTRIBUTE_GENERATED_VIRTUAL)
601 5246 : constr->has_generated_virtual = true;
602 3707831 : if (attp->atthasdef)
603 37233 : ndef++;
604 :
605 : /* If the column has a "missing" value, put it in the attrmiss array */
606 3707831 : if (attp->atthasmissing)
607 : {
608 : Datum missingval;
609 : bool missingNull;
610 :
611 : /* Do we have a missing value? */
612 5471 : missingval = heap_getattr(pg_attribute_tuple,
613 : Anum_pg_attribute_attmissingval,
614 : pg_attribute_desc->rd_att,
615 : &missingNull);
616 5471 : if (!missingNull)
617 : {
618 : /* Yes, fetch from the array */
619 : MemoryContext oldcxt;
620 : bool is_null;
621 5471 : int one = 1;
622 : Datum missval;
623 :
624 5471 : if (attrmiss == NULL)
625 : attrmiss = (AttrMissing *)
626 2642 : MemoryContextAllocZero(CacheMemoryContext,
627 2642 : relation->rd_rel->relnatts *
628 : sizeof(AttrMissing));
629 :
630 5471 : missval = array_get_element(missingval,
631 : 1,
632 : &one,
633 : -1,
634 5471 : attp->attlen,
635 5471 : attp->attbyval,
636 5471 : attp->attalign,
637 : &is_null);
638 : Assert(!is_null);
639 5471 : if (attp->attbyval)
640 : {
641 : /* for copy by val just copy the datum direct */
642 3434 : attrmiss[attnum - 1].am_value = missval;
643 : }
644 : else
645 : {
646 : /* otherwise copy in the correct context */
647 2037 : oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
648 4074 : attrmiss[attnum - 1].am_value = datumCopy(missval,
649 2037 : attp->attbyval,
650 2037 : attp->attlen);
651 2037 : MemoryContextSwitchTo(oldcxt);
652 : }
653 5471 : attrmiss[attnum - 1].am_present = true;
654 : }
655 : }
656 3707831 : need--;
657 3707831 : if (need == 0)
658 1068179 : break;
659 : }
660 :
661 : /*
662 : * end the scan and close the attribute relation
663 : */
664 1073632 : systable_endscan(pg_attribute_scan);
665 1073632 : table_close(pg_attribute_desc, AccessShareLock);
666 :
667 1073632 : if (need != 0)
668 0 : elog(ERROR, "pg_attribute catalog is missing %d attribute(s) for relation OID %u",
669 : need, RelationGetRelid(relation));
670 :
671 : /*
672 : * Set up constraint/default info
673 : */
674 1073632 : if (constr->has_not_null ||
675 750194 : constr->has_generated_stored ||
676 746955 : constr->has_generated_virtual ||
677 742235 : ndef > 0 ||
678 742203 : attrmiss ||
679 742203 : relation->rd_rel->relchecks > 0)
680 335517 : {
681 335517 : bool is_catalog = IsCatalogRelation(relation);
682 :
683 335517 : relation->rd_att->constr = constr;
684 :
685 335517 : if (ndef > 0) /* DEFAULTs */
686 25785 : AttrDefaultFetch(relation, ndef);
687 : else
688 309732 : constr->num_defval = 0;
689 :
690 335517 : constr->missing = attrmiss;
691 :
692 : /* CHECK and NOT NULLs */
693 335517 : if (relation->rd_rel->relchecks > 0 ||
694 326271 : (!is_catalog && constr->has_not_null))
695 116078 : CheckNNConstraintFetch(relation);
696 :
697 : /*
698 : * Any not-null constraint that wasn't marked invalid by
699 : * CheckNNConstraintFetch must necessarily be valid; make it so in the
700 : * CompactAttribute array.
701 : */
702 335517 : if (!is_catalog)
703 : {
704 435996 : for (int i = 0; i < relation->rd_rel->relnatts; i++)
705 : {
706 : CompactAttribute *attr;
707 :
708 312427 : attr = TupleDescCompactAttr(relation->rd_att, i);
709 :
710 312427 : if (attr->attnullability == ATTNULLABLE_UNKNOWN)
711 163043 : attr->attnullability = ATTNULLABLE_VALID;
712 : else
713 : Assert(attr->attnullability == ATTNULLABLE_INVALID ||
714 : attr->attnullability == ATTNULLABLE_UNRESTRICTED);
715 : }
716 : }
717 :
718 335517 : if (relation->rd_rel->relchecks == 0)
719 326271 : constr->num_check = 0;
720 : }
721 : else
722 : {
723 738115 : pfree(constr);
724 738115 : relation->rd_att->constr = NULL;
725 : }
726 :
727 1073632 : TupleDescFinalize(relation->rd_att);
728 1073632 : }
729 :
730 : /*
731 : * RelationBuildRuleLock
732 : *
733 : * Form the relation's rewrite rules from information in
734 : * the pg_rewrite system catalog.
735 : *
736 : * Note: The rule parsetrees are potentially very complex node structures.
737 : * To allow these trees to be freed when the relcache entry is flushed,
738 : * we make a private memory context to hold the RuleLock information for
739 : * each relcache entry that has associated rules. The context is used
740 : * just for rule info, not for any other subsidiary data of the relcache
741 : * entry, because that keeps the update logic in RelationRebuildRelation()
742 : * manageable. The other subsidiary data structures are simple enough
743 : * to be easy to free explicitly, anyway.
744 : *
745 : * Note: The relation's reloptions must have been extracted first.
746 : */
747 : static void
748 25019 : RelationBuildRuleLock(Relation relation)
749 : {
750 : MemoryContext rulescxt;
751 : MemoryContext oldcxt;
752 : HeapTuple rewrite_tuple;
753 : Relation rewrite_desc;
754 : TupleDesc rewrite_tupdesc;
755 : SysScanDesc rewrite_scan;
756 : ScanKeyData key;
757 : RuleLock *rulelock;
758 : int numlocks;
759 : RewriteRule **rules;
760 : int maxlocks;
761 :
762 : /*
763 : * Make the private context. Assume it'll not contain much data.
764 : */
765 25019 : rulescxt = AllocSetContextCreate(CacheMemoryContext,
766 : "relation rules",
767 : ALLOCSET_SMALL_SIZES);
768 25019 : relation->rd_rulescxt = rulescxt;
769 25019 : MemoryContextCopyAndSetIdentifier(rulescxt,
770 : RelationGetRelationName(relation));
771 :
772 : /*
773 : * allocate an array to hold the rewrite rules (the array is extended if
774 : * necessary)
775 : */
776 25019 : maxlocks = 4;
777 : rules = (RewriteRule **)
778 25019 : MemoryContextAlloc(rulescxt, sizeof(RewriteRule *) * maxlocks);
779 25019 : numlocks = 0;
780 :
781 : /*
782 : * form a scan key
783 : */
784 25019 : ScanKeyInit(&key,
785 : Anum_pg_rewrite_ev_class,
786 : BTEqualStrategyNumber, F_OIDEQ,
787 : ObjectIdGetDatum(RelationGetRelid(relation)));
788 :
789 : /*
790 : * open pg_rewrite and begin a scan
791 : *
792 : * Note: since we scan the rules using RewriteRelRulenameIndexId, we will
793 : * be reading the rules in name order, except possibly during
794 : * emergency-recovery operations (ie, IgnoreSystemIndexes). This in turn
795 : * ensures that rules will be fired in name order.
796 : */
797 25019 : rewrite_desc = table_open(RewriteRelationId, AccessShareLock);
798 25019 : rewrite_tupdesc = RelationGetDescr(rewrite_desc);
799 25019 : rewrite_scan = systable_beginscan(rewrite_desc,
800 : RewriteRelRulenameIndexId,
801 : true, NULL,
802 : 1, &key);
803 :
804 49699 : while (HeapTupleIsValid(rewrite_tuple = systable_getnext(rewrite_scan)))
805 : {
806 24680 : Form_pg_rewrite rewrite_form = (Form_pg_rewrite) GETSTRUCT(rewrite_tuple);
807 : bool isnull;
808 : Datum rule_datum;
809 : char *rule_str;
810 : RewriteRule *rule;
811 : Oid check_as_user;
812 :
813 24680 : rule = (RewriteRule *) MemoryContextAlloc(rulescxt,
814 : sizeof(RewriteRule));
815 :
816 24680 : rule->ruleId = rewrite_form->oid;
817 :
818 24680 : rule->event = rewrite_form->ev_type - '0';
819 24680 : rule->enabled = rewrite_form->ev_enabled;
820 24680 : rule->isInstead = rewrite_form->is_instead;
821 :
822 : /*
823 : * Must use heap_getattr to fetch ev_action and ev_qual. Also, the
824 : * rule strings are often large enough to be toasted. To avoid
825 : * leaking memory in the caller's context, do the detoasting here so
826 : * we can free the detoasted version.
827 : */
828 24680 : rule_datum = heap_getattr(rewrite_tuple,
829 : Anum_pg_rewrite_ev_action,
830 : rewrite_tupdesc,
831 : &isnull);
832 : Assert(!isnull);
833 24680 : rule_str = TextDatumGetCString(rule_datum);
834 24680 : oldcxt = MemoryContextSwitchTo(rulescxt);
835 24680 : rule->actions = (List *) stringToNode(rule_str);
836 24680 : MemoryContextSwitchTo(oldcxt);
837 24680 : pfree(rule_str);
838 :
839 24680 : rule_datum = heap_getattr(rewrite_tuple,
840 : Anum_pg_rewrite_ev_qual,
841 : rewrite_tupdesc,
842 : &isnull);
843 : Assert(!isnull);
844 24680 : rule_str = TextDatumGetCString(rule_datum);
845 24680 : oldcxt = MemoryContextSwitchTo(rulescxt);
846 24680 : rule->qual = (Node *) stringToNode(rule_str);
847 24680 : MemoryContextSwitchTo(oldcxt);
848 24680 : pfree(rule_str);
849 :
850 : /*
851 : * If this is a SELECT rule defining a view, and the view has
852 : * "security_invoker" set, we must perform all permissions checks on
853 : * relations referred to by the rule as the invoking user.
854 : *
855 : * In all other cases (including non-SELECT rules on security invoker
856 : * views), perform the permissions checks as the relation owner.
857 : */
858 24680 : if (rule->event == CMD_SELECT &&
859 22346 : relation->rd_rel->relkind == RELKIND_VIEW &&
860 20019 : RelationHasSecurityInvoker(relation))
861 112 : check_as_user = InvalidOid;
862 : else
863 24568 : check_as_user = relation->rd_rel->relowner;
864 :
865 : /*
866 : * Scan through the rule's actions and set the checkAsUser field on
867 : * all RTEPermissionInfos. We have to look at the qual as well, in
868 : * case it contains sublinks.
869 : *
870 : * The reason for doing this when the rule is loaded, rather than when
871 : * it is stored, is that otherwise ALTER TABLE OWNER would have to
872 : * grovel through stored rules to update checkAsUser fields. Scanning
873 : * the rule tree during load is relatively cheap (compared to
874 : * constructing it in the first place), so we do it here.
875 : */
876 24680 : setRuleCheckAsUser((Node *) rule->actions, check_as_user);
877 24680 : setRuleCheckAsUser(rule->qual, check_as_user);
878 :
879 24680 : if (numlocks >= maxlocks)
880 : {
881 19 : maxlocks *= 2;
882 : rules = (RewriteRule **)
883 19 : repalloc(rules, sizeof(RewriteRule *) * maxlocks);
884 : }
885 24680 : rules[numlocks++] = rule;
886 : }
887 :
888 : /*
889 : * end the scan and close the attribute relation
890 : */
891 25019 : systable_endscan(rewrite_scan);
892 25019 : table_close(rewrite_desc, AccessShareLock);
893 :
894 : /*
895 : * there might not be any rules (if relhasrules is out-of-date)
896 : */
897 25019 : if (numlocks == 0)
898 : {
899 2028 : relation->rd_rules = NULL;
900 2028 : relation->rd_rulescxt = NULL;
901 2028 : MemoryContextDelete(rulescxt);
902 2028 : return;
903 : }
904 :
905 : /*
906 : * form a RuleLock and insert into relation
907 : */
908 22991 : rulelock = (RuleLock *) MemoryContextAlloc(rulescxt, sizeof(RuleLock));
909 22991 : rulelock->numLocks = numlocks;
910 22991 : rulelock->rules = rules;
911 :
912 22991 : relation->rd_rules = rulelock;
913 : }
914 :
915 : /*
916 : * equalRuleLocks
917 : *
918 : * Determine whether two RuleLocks are equivalent
919 : *
920 : * Probably this should be in the rules code someplace...
921 : */
922 : static bool
923 282975 : equalRuleLocks(RuleLock *rlock1, RuleLock *rlock2)
924 : {
925 : int i;
926 :
927 : /*
928 : * As of 7.3 we assume the rule ordering is repeatable, because
929 : * RelationBuildRuleLock should read 'em in a consistent order. So just
930 : * compare corresponding slots.
931 : */
932 282975 : if (rlock1 != NULL)
933 : {
934 1735 : if (rlock2 == NULL)
935 43 : return false;
936 1692 : if (rlock1->numLocks != rlock2->numLocks)
937 4 : return false;
938 3208 : for (i = 0; i < rlock1->numLocks; i++)
939 : {
940 1715 : RewriteRule *rule1 = rlock1->rules[i];
941 1715 : RewriteRule *rule2 = rlock2->rules[i];
942 :
943 1715 : if (rule1->ruleId != rule2->ruleId)
944 0 : return false;
945 1715 : if (rule1->event != rule2->event)
946 0 : return false;
947 1715 : if (rule1->enabled != rule2->enabled)
948 29 : return false;
949 1686 : if (rule1->isInstead != rule2->isInstead)
950 0 : return false;
951 1686 : if (!equal(rule1->qual, rule2->qual))
952 0 : return false;
953 1686 : if (!equal(rule1->actions, rule2->actions))
954 166 : return false;
955 : }
956 : }
957 281240 : else if (rlock2 != NULL)
958 11008 : return false;
959 271725 : return true;
960 : }
961 :
962 : /*
963 : * equalPolicy
964 : *
965 : * Determine whether two policies are equivalent
966 : */
967 : static bool
968 328 : equalPolicy(RowSecurityPolicy *policy1, RowSecurityPolicy *policy2)
969 : {
970 : int i;
971 : Oid *r1,
972 : *r2;
973 :
974 328 : if (policy1 != NULL)
975 : {
976 328 : if (policy2 == NULL)
977 0 : return false;
978 :
979 328 : if (policy1->polcmd != policy2->polcmd)
980 0 : return false;
981 328 : if (policy1->hassublinks != policy2->hassublinks)
982 0 : return false;
983 328 : if (strcmp(policy1->policy_name, policy2->policy_name) != 0)
984 0 : return false;
985 328 : if (ARR_DIMS(policy1->roles)[0] != ARR_DIMS(policy2->roles)[0])
986 0 : return false;
987 :
988 328 : r1 = (Oid *) ARR_DATA_PTR(policy1->roles);
989 328 : r2 = (Oid *) ARR_DATA_PTR(policy2->roles);
990 :
991 656 : for (i = 0; i < ARR_DIMS(policy1->roles)[0]; i++)
992 : {
993 328 : if (r1[i] != r2[i])
994 0 : return false;
995 : }
996 :
997 328 : if (!equal(policy1->qual, policy2->qual))
998 0 : return false;
999 328 : if (!equal(policy1->with_check_qual, policy2->with_check_qual))
1000 0 : return false;
1001 : }
1002 0 : else if (policy2 != NULL)
1003 0 : return false;
1004 :
1005 328 : return true;
1006 : }
1007 :
1008 : /*
1009 : * equalRSDesc
1010 : *
1011 : * Determine whether two RowSecurityDesc's are equivalent
1012 : */
1013 : static bool
1014 282975 : equalRSDesc(RowSecurityDesc *rsdesc1, RowSecurityDesc *rsdesc2)
1015 : {
1016 : ListCell *lc,
1017 : *rc;
1018 :
1019 282975 : if (rsdesc1 == NULL && rsdesc2 == NULL)
1020 282551 : return true;
1021 :
1022 424 : if ((rsdesc1 != NULL && rsdesc2 == NULL) ||
1023 240 : (rsdesc1 == NULL && rsdesc2 != NULL))
1024 246 : return false;
1025 :
1026 178 : if (list_length(rsdesc1->policies) != list_length(rsdesc2->policies))
1027 4 : return false;
1028 :
1029 : /* RelationBuildRowSecurity should build policies in order */
1030 502 : forboth(lc, rsdesc1->policies, rc, rsdesc2->policies)
1031 : {
1032 328 : RowSecurityPolicy *l = (RowSecurityPolicy *) lfirst(lc);
1033 328 : RowSecurityPolicy *r = (RowSecurityPolicy *) lfirst(rc);
1034 :
1035 328 : if (!equalPolicy(l, r))
1036 0 : return false;
1037 : }
1038 :
1039 174 : return true;
1040 : }
1041 :
1042 : /*
1043 : * RelationBuildDesc
1044 : *
1045 : * Build a relation descriptor. The caller must hold at least
1046 : * AccessShareLock on the target relid.
1047 : *
1048 : * The new descriptor is inserted into the hash table if insertIt is true.
1049 : *
1050 : * Returns NULL if no pg_class row could be found for the given relid
1051 : * (suggesting we are trying to access a just-deleted relation).
1052 : * Any other error is reported via elog.
1053 : */
1054 : static Relation
1055 1073629 : RelationBuildDesc(Oid targetRelId, bool insertIt)
1056 : {
1057 : int in_progress_offset;
1058 : Relation relation;
1059 : Oid relid;
1060 : HeapTuple pg_class_tuple;
1061 : Form_pg_class relp;
1062 :
1063 : /*
1064 : * This function and its subroutines can allocate a good deal of transient
1065 : * data in CurrentMemoryContext. Traditionally we've just leaked that
1066 : * data, reasoning that the caller's context is at worst of transaction
1067 : * scope, and relcache loads shouldn't happen so often that it's essential
1068 : * to recover transient data before end of statement/transaction. However
1069 : * that's definitely not true when debug_discard_caches is active, and
1070 : * perhaps it's not true in other cases.
1071 : *
1072 : * When debug_discard_caches is active or when forced to by
1073 : * RECOVER_RELATION_BUILD_MEMORY=1, arrange to allocate the junk in a
1074 : * temporary context that we'll free before returning. Make it a child of
1075 : * caller's context so that it will get cleaned up appropriately if we
1076 : * error out partway through.
1077 : */
1078 : #ifdef MAYBE_RECOVER_RELATION_BUILD_MEMORY
1079 : MemoryContext tmpcxt = NULL;
1080 : MemoryContext oldcxt = NULL;
1081 :
1082 : if (RECOVER_RELATION_BUILD_MEMORY || debug_discard_caches > 0)
1083 : {
1084 : tmpcxt = AllocSetContextCreate(CurrentMemoryContext,
1085 : "RelationBuildDesc workspace",
1086 : ALLOCSET_DEFAULT_SIZES);
1087 : oldcxt = MemoryContextSwitchTo(tmpcxt);
1088 : }
1089 : #endif
1090 :
1091 : /* Register to catch invalidation messages */
1092 1073629 : if (in_progress_list_len >= in_progress_list_maxlen)
1093 : {
1094 : int allocsize;
1095 :
1096 16 : allocsize = in_progress_list_maxlen * 2;
1097 16 : in_progress_list = repalloc(in_progress_list,
1098 : allocsize * sizeof(*in_progress_list));
1099 16 : in_progress_list_maxlen = allocsize;
1100 : }
1101 1073629 : in_progress_offset = in_progress_list_len++;
1102 1073629 : in_progress_list[in_progress_offset].reloid = targetRelId;
1103 1073638 : retry:
1104 1073638 : in_progress_list[in_progress_offset].invalidated = false;
1105 :
1106 : /*
1107 : * find the tuple in pg_class corresponding to the given relation id
1108 : */
1109 1073638 : pg_class_tuple = ScanPgRelation(targetRelId, true, false);
1110 :
1111 : /*
1112 : * if no such tuple exists, return NULL
1113 : */
1114 1073638 : if (!HeapTupleIsValid(pg_class_tuple))
1115 : {
1116 : #ifdef MAYBE_RECOVER_RELATION_BUILD_MEMORY
1117 : if (tmpcxt)
1118 : {
1119 : /* Return to caller's context, and blow away the temporary context */
1120 : MemoryContextSwitchTo(oldcxt);
1121 : MemoryContextDelete(tmpcxt);
1122 : }
1123 : #endif
1124 : Assert(in_progress_offset + 1 == in_progress_list_len);
1125 6 : in_progress_list_len--;
1126 6 : return NULL;
1127 : }
1128 :
1129 : /*
1130 : * get information from the pg_class_tuple
1131 : */
1132 1073632 : relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
1133 1073632 : relid = relp->oid;
1134 : Assert(relid == targetRelId);
1135 :
1136 : /*
1137 : * allocate storage for the relation descriptor, and copy pg_class_tuple
1138 : * to relation->rd_rel.
1139 : */
1140 1073632 : relation = AllocateRelationDesc(relp);
1141 :
1142 : /*
1143 : * initialize the relation's relation id (relation->rd_id)
1144 : */
1145 1073632 : RelationGetRelid(relation) = relid;
1146 :
1147 : /*
1148 : * Normal relations are not nailed into the cache. Since we don't flush
1149 : * new relations, it won't be new. It could be temp though.
1150 : */
1151 1073632 : relation->rd_refcnt = 0;
1152 1073632 : relation->rd_isnailed = false;
1153 1073632 : relation->rd_createSubid = InvalidSubTransactionId;
1154 1073632 : relation->rd_newRelfilelocatorSubid = InvalidSubTransactionId;
1155 1073632 : relation->rd_firstRelfilelocatorSubid = InvalidSubTransactionId;
1156 1073632 : relation->rd_droppedSubid = InvalidSubTransactionId;
1157 1073632 : switch (relation->rd_rel->relpersistence)
1158 : {
1159 1052915 : case RELPERSISTENCE_UNLOGGED:
1160 : case RELPERSISTENCE_PERMANENT:
1161 1052915 : relation->rd_backend = INVALID_PROC_NUMBER;
1162 1052915 : relation->rd_islocaltemp = false;
1163 1052915 : break;
1164 20717 : case RELPERSISTENCE_TEMP:
1165 20717 : if (isTempOrTempToastNamespace(relation->rd_rel->relnamespace))
1166 : {
1167 20684 : relation->rd_backend = ProcNumberForTempRelations();
1168 20684 : relation->rd_islocaltemp = true;
1169 : }
1170 : else
1171 : {
1172 : /*
1173 : * If it's a temp table, but not one of ours, we have to use
1174 : * the slow, grotty method to figure out the owning backend.
1175 : *
1176 : * Note: it's possible that rd_backend gets set to
1177 : * MyProcNumber here, in case we are looking at a pg_class
1178 : * entry left over from a crashed backend that coincidentally
1179 : * had the same ProcNumber we're using. We should *not*
1180 : * consider such a table to be "ours"; this is why we need the
1181 : * separate rd_islocaltemp flag. The pg_class entry will get
1182 : * flushed if/when we clean out the corresponding temp table
1183 : * namespace in preparation for using it.
1184 : */
1185 33 : relation->rd_backend =
1186 33 : GetTempNamespaceProcNumber(relation->rd_rel->relnamespace);
1187 : Assert(relation->rd_backend != INVALID_PROC_NUMBER);
1188 33 : relation->rd_islocaltemp = false;
1189 : }
1190 20717 : break;
1191 0 : default:
1192 0 : elog(ERROR, "invalid relpersistence: %c",
1193 : relation->rd_rel->relpersistence);
1194 : break;
1195 : }
1196 :
1197 : /*
1198 : * initialize the tuple descriptor (relation->rd_att).
1199 : */
1200 1073632 : RelationBuildTupleDesc(relation);
1201 :
1202 : /* foreign key data is not loaded till asked for */
1203 1073632 : relation->rd_fkeylist = NIL;
1204 1073632 : relation->rd_fkeyvalid = false;
1205 :
1206 : /* partitioning data is not loaded till asked for */
1207 1073632 : relation->rd_partkey = NULL;
1208 1073632 : relation->rd_partkeycxt = NULL;
1209 1073632 : relation->rd_partdesc = NULL;
1210 1073632 : relation->rd_partdesc_nodetached = NULL;
1211 1073632 : relation->rd_partdesc_nodetached_xmin = InvalidTransactionId;
1212 1073632 : relation->rd_pdcxt = NULL;
1213 1073632 : relation->rd_pddcxt = NULL;
1214 1073632 : relation->rd_partcheck = NIL;
1215 1073632 : relation->rd_partcheckvalid = false;
1216 1073632 : relation->rd_partcheckcxt = NULL;
1217 :
1218 : /*
1219 : * initialize access method information
1220 : */
1221 1073632 : if (relation->rd_rel->relkind == RELKIND_INDEX ||
1222 644684 : relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX)
1223 433593 : RelationInitIndexAccessInfo(relation);
1224 640039 : else if (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind) ||
1225 86861 : relation->rd_rel->relkind == RELKIND_SEQUENCE)
1226 556946 : RelationInitTableAccessMethod(relation);
1227 : else if (relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
1228 : {
1229 : /*
1230 : * Do nothing: access methods are a setting that partitions can
1231 : * inherit.
1232 : */
1233 : }
1234 : else
1235 : Assert(relation->rd_rel->relam == InvalidOid);
1236 :
1237 : /* extract reloptions if any */
1238 1073628 : RelationParseRelOptions(relation, pg_class_tuple);
1239 :
1240 : /*
1241 : * Fetch rules and triggers that affect this relation.
1242 : *
1243 : * Note that RelationBuildRuleLock() relies on this being done after
1244 : * extracting the relation's reloptions.
1245 : */
1246 1073628 : if (relation->rd_rel->relhasrules)
1247 25019 : RelationBuildRuleLock(relation);
1248 : else
1249 : {
1250 1048609 : relation->rd_rules = NULL;
1251 1048609 : relation->rd_rulescxt = NULL;
1252 : }
1253 :
1254 1073628 : if (relation->rd_rel->relhastriggers)
1255 42363 : RelationBuildTriggers(relation);
1256 : else
1257 1031265 : relation->trigdesc = NULL;
1258 :
1259 1073628 : if (relation->rd_rel->relrowsecurity)
1260 1795 : RelationBuildRowSecurity(relation);
1261 : else
1262 1071833 : relation->rd_rsdesc = NULL;
1263 :
1264 : /*
1265 : * initialize the relation lock manager information
1266 : */
1267 1073628 : RelationInitLockInfo(relation); /* see lmgr.c */
1268 :
1269 : /*
1270 : * initialize physical addressing information for the relation
1271 : */
1272 1073628 : RelationInitPhysicalAddr(relation);
1273 :
1274 : /* make sure relation is marked as having no open file yet */
1275 1073628 : relation->rd_smgr = NULL;
1276 :
1277 : /*
1278 : * now we can free the memory allocated for pg_class_tuple
1279 : */
1280 1073628 : heap_freetuple(pg_class_tuple);
1281 :
1282 : /*
1283 : * If an invalidation arrived mid-build, start over. Between here and the
1284 : * end of this function, don't add code that does or reasonably could read
1285 : * system catalogs. That range must be free from invalidation processing
1286 : * for the !insertIt case. For the insertIt case, RelationCacheInsert()
1287 : * will enroll this relation in ordinary relcache invalidation processing,
1288 : */
1289 1073628 : if (in_progress_list[in_progress_offset].invalidated)
1290 : {
1291 9 : RelationDestroyRelation(relation, false);
1292 9 : goto retry;
1293 : }
1294 : Assert(in_progress_offset + 1 == in_progress_list_len);
1295 1073619 : in_progress_list_len--;
1296 :
1297 : /*
1298 : * Insert newly created relation into relcache hash table, if requested.
1299 : *
1300 : * There is one scenario in which we might find a hashtable entry already
1301 : * present, even though our caller failed to find it: if the relation is a
1302 : * system catalog or index that's used during relcache load, we might have
1303 : * recursively created the same relcache entry during the preceding steps.
1304 : * So allow RelationCacheInsert to delete any already-present relcache
1305 : * entry for the same OID. The already-present entry should have refcount
1306 : * zero (else somebody forgot to close it); in the event that it doesn't,
1307 : * we'll elog a WARNING and leak the already-present entry.
1308 : */
1309 1073619 : if (insertIt)
1310 790644 : RelationCacheInsert(relation, true);
1311 :
1312 : /* It's fully valid */
1313 1073619 : relation->rd_isvalid = true;
1314 :
1315 : #ifdef MAYBE_RECOVER_RELATION_BUILD_MEMORY
1316 : if (tmpcxt)
1317 : {
1318 : /* Return to caller's context, and blow away the temporary context */
1319 : MemoryContextSwitchTo(oldcxt);
1320 : MemoryContextDelete(tmpcxt);
1321 : }
1322 : #endif
1323 :
1324 1073619 : return relation;
1325 : }
1326 :
1327 : /*
1328 : * Initialize the physical addressing info (RelFileLocator) for a relcache entry
1329 : *
1330 : * Note: at the physical level, relations in the pg_global tablespace must
1331 : * be treated as shared, even if relisshared isn't set. Hence we do not
1332 : * look at relisshared here.
1333 : */
1334 : static void
1335 3955561 : RelationInitPhysicalAddr(Relation relation)
1336 : {
1337 3955561 : RelFileNumber oldnumber = relation->rd_locator.relNumber;
1338 :
1339 : /* these relations kinds never have storage */
1340 3955561 : if (!RELKIND_HAS_STORAGE(relation->rd_rel->relkind))
1341 108985 : return;
1342 :
1343 3846576 : if (relation->rd_rel->reltablespace)
1344 567196 : relation->rd_locator.spcOid = relation->rd_rel->reltablespace;
1345 : else
1346 3279380 : relation->rd_locator.spcOid = MyDatabaseTableSpace;
1347 3846576 : if (relation->rd_locator.spcOid == GLOBALTABLESPACE_OID)
1348 564686 : relation->rd_locator.dbOid = InvalidOid;
1349 : else
1350 3281890 : relation->rd_locator.dbOid = MyDatabaseId;
1351 :
1352 3846576 : if (relation->rd_rel->relfilenode)
1353 : {
1354 : /*
1355 : * Even if we are using a decoding snapshot that doesn't represent the
1356 : * current state of the catalog we need to make sure the filenode
1357 : * points to the current file since the older file will be gone (or
1358 : * truncated). The new file will still contain older rows so lookups
1359 : * in them will work correctly. This wouldn't work correctly if
1360 : * rewrites were allowed to change the schema in an incompatible way,
1361 : * but those are prevented both on catalog tables and on user tables
1362 : * declared as additional catalog tables.
1363 : */
1364 2924195 : if (HistoricSnapshotActive()
1365 2859 : && RelationIsAccessibleInLogicalDecoding(relation)
1366 1884 : && IsTransactionState())
1367 : {
1368 : HeapTuple phys_tuple;
1369 : Form_pg_class physrel;
1370 :
1371 1884 : phys_tuple = ScanPgRelation(RelationGetRelid(relation),
1372 1884 : RelationGetRelid(relation) != ClassOidIndexId,
1373 : true);
1374 1884 : if (!HeapTupleIsValid(phys_tuple))
1375 0 : elog(ERROR, "could not find pg_class entry for %u",
1376 : RelationGetRelid(relation));
1377 1884 : physrel = (Form_pg_class) GETSTRUCT(phys_tuple);
1378 :
1379 1884 : relation->rd_rel->reltablespace = physrel->reltablespace;
1380 1884 : relation->rd_rel->relfilenode = physrel->relfilenode;
1381 1884 : heap_freetuple(phys_tuple);
1382 : }
1383 :
1384 2924195 : relation->rd_locator.relNumber = relation->rd_rel->relfilenode;
1385 : }
1386 : else
1387 : {
1388 : /* Consult the relation mapper */
1389 922381 : relation->rd_locator.relNumber =
1390 922381 : RelationMapOidToFilenumber(relation->rd_id,
1391 922381 : relation->rd_rel->relisshared);
1392 922381 : if (!RelFileNumberIsValid(relation->rd_locator.relNumber))
1393 0 : elog(ERROR, "could not find relation mapping for relation \"%s\", OID %u",
1394 : RelationGetRelationName(relation), relation->rd_id);
1395 : }
1396 :
1397 : /*
1398 : * For RelationNeedsWAL() to answer correctly on parallel workers, restore
1399 : * rd_firstRelfilelocatorSubid. No subtransactions start or end while in
1400 : * parallel mode, so the specific SubTransactionId does not matter.
1401 : */
1402 3846576 : if (IsParallelWorker() && oldnumber != relation->rd_locator.relNumber)
1403 : {
1404 43212 : if (RelFileLocatorSkippingWAL(relation->rd_locator))
1405 3 : relation->rd_firstRelfilelocatorSubid = TopSubTransactionId;
1406 : else
1407 43209 : relation->rd_firstRelfilelocatorSubid = InvalidSubTransactionId;
1408 : }
1409 : }
1410 :
1411 : /*
1412 : * Fill in the IndexAmRoutine for an index relation.
1413 : *
1414 : * relation's rd_amhandler and rd_indexcxt must be valid already.
1415 : */
1416 : static void
1417 2035859 : InitIndexAmRoutine(Relation relation)
1418 : {
1419 : MemoryContext oldctx;
1420 :
1421 : /*
1422 : * We formerly specified that the amhandler should return a palloc'd
1423 : * struct. That's now deprecated in favor of returning a pointer to a
1424 : * static struct, but to avoid completely breaking old external AMs, run
1425 : * the amhandler in the relation's rd_indexcxt.
1426 : */
1427 2035859 : oldctx = MemoryContextSwitchTo(relation->rd_indexcxt);
1428 2035859 : relation->rd_indam = GetIndexAmRoutine(relation->rd_amhandler);
1429 2035859 : MemoryContextSwitchTo(oldctx);
1430 2035859 : }
1431 :
1432 : /*
1433 : * Initialize index-access-method support data for an index relation
1434 : */
1435 : void
1436 443397 : RelationInitIndexAccessInfo(Relation relation)
1437 : {
1438 : HeapTuple tuple;
1439 : Form_pg_am aform;
1440 : Datum indcollDatum;
1441 : Datum indclassDatum;
1442 : Datum indoptionDatum;
1443 : bool isnull;
1444 : oidvector *indcoll;
1445 : oidvector *indclass;
1446 : int2vector *indoption;
1447 : MemoryContext indexcxt;
1448 : MemoryContext oldcontext;
1449 : int indnatts;
1450 : int indnkeyatts;
1451 : uint16 amsupport;
1452 :
1453 : /*
1454 : * Make a copy of the pg_index entry for the index. Since pg_index
1455 : * contains variable-length and possibly-null fields, we have to do this
1456 : * honestly rather than just treating it as a Form_pg_index struct.
1457 : */
1458 443397 : tuple = SearchSysCache1(INDEXRELID,
1459 : ObjectIdGetDatum(RelationGetRelid(relation)));
1460 443397 : if (!HeapTupleIsValid(tuple))
1461 0 : elog(ERROR, "cache lookup failed for index %u",
1462 : RelationGetRelid(relation));
1463 443397 : oldcontext = MemoryContextSwitchTo(CacheMemoryContext);
1464 443397 : relation->rd_indextuple = heap_copytuple(tuple);
1465 443397 : relation->rd_index = (Form_pg_index) GETSTRUCT(relation->rd_indextuple);
1466 443397 : MemoryContextSwitchTo(oldcontext);
1467 443397 : ReleaseSysCache(tuple);
1468 :
1469 : /*
1470 : * Look up the index's access method, save the OID of its handler function
1471 : */
1472 : Assert(relation->rd_rel->relam != InvalidOid);
1473 443397 : tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(relation->rd_rel->relam));
1474 443397 : if (!HeapTupleIsValid(tuple))
1475 0 : elog(ERROR, "cache lookup failed for access method %u",
1476 : relation->rd_rel->relam);
1477 443397 : aform = (Form_pg_am) GETSTRUCT(tuple);
1478 443397 : relation->rd_amhandler = aform->amhandler;
1479 443397 : ReleaseSysCache(tuple);
1480 :
1481 443397 : indnatts = RelationGetNumberOfAttributes(relation);
1482 443397 : if (indnatts != IndexRelationGetNumberOfAttributes(relation))
1483 0 : elog(ERROR, "relnatts disagrees with indnatts for index %u",
1484 : RelationGetRelid(relation));
1485 443397 : indnkeyatts = IndexRelationGetNumberOfKeyAttributes(relation);
1486 :
1487 : /*
1488 : * Make the private context to hold index access info. The reason we need
1489 : * a context, and not just a couple of pallocs, is so that we won't leak
1490 : * any subsidiary info attached to fmgr lookup records.
1491 : */
1492 443397 : indexcxt = AllocSetContextCreate(CacheMemoryContext,
1493 : "index info",
1494 : ALLOCSET_SMALL_SIZES);
1495 443397 : relation->rd_indexcxt = indexcxt;
1496 443397 : MemoryContextCopyAndSetIdentifier(indexcxt,
1497 : RelationGetRelationName(relation));
1498 :
1499 : /*
1500 : * Now we can fetch the index AM's API struct
1501 : */
1502 443397 : InitIndexAmRoutine(relation);
1503 :
1504 : /*
1505 : * Allocate arrays to hold data. Opclasses are not used for included
1506 : * columns, so allocate them for indnkeyatts only.
1507 : */
1508 443397 : relation->rd_opfamily = (Oid *)
1509 443397 : MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1510 443397 : relation->rd_opcintype = (Oid *)
1511 443397 : MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1512 :
1513 443397 : amsupport = relation->rd_indam->amsupport;
1514 443397 : if (amsupport > 0)
1515 : {
1516 443397 : int nsupport = indnatts * amsupport;
1517 :
1518 443397 : relation->rd_support = (RegProcedure *)
1519 443397 : MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
1520 443397 : relation->rd_supportinfo = (FmgrInfo *)
1521 443397 : MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
1522 : }
1523 : else
1524 : {
1525 0 : relation->rd_support = NULL;
1526 0 : relation->rd_supportinfo = NULL;
1527 : }
1528 :
1529 443397 : relation->rd_indcollation = (Oid *)
1530 443397 : MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(Oid));
1531 :
1532 443397 : relation->rd_indoption = (int16 *)
1533 443397 : MemoryContextAllocZero(indexcxt, indnkeyatts * sizeof(int16));
1534 :
1535 : /*
1536 : * indcollation cannot be referenced directly through the C struct,
1537 : * because it comes after the variable-width indkey field. Must extract
1538 : * the datum the hard way...
1539 : */
1540 443397 : indcollDatum = fastgetattr(relation->rd_indextuple,
1541 : Anum_pg_index_indcollation,
1542 : GetPgIndexDescriptor(),
1543 : &isnull);
1544 : Assert(!isnull);
1545 443397 : indcoll = (oidvector *) DatumGetPointer(indcollDatum);
1546 443397 : memcpy(relation->rd_indcollation, indcoll->values, indnkeyatts * sizeof(Oid));
1547 :
1548 : /*
1549 : * indclass cannot be referenced directly through the C struct, because it
1550 : * comes after the variable-width indkey field. Must extract the datum
1551 : * the hard way...
1552 : */
1553 443397 : indclassDatum = fastgetattr(relation->rd_indextuple,
1554 : Anum_pg_index_indclass,
1555 : GetPgIndexDescriptor(),
1556 : &isnull);
1557 : Assert(!isnull);
1558 443397 : indclass = (oidvector *) DatumGetPointer(indclassDatum);
1559 :
1560 : /*
1561 : * Fill the support procedure OID array, as well as the info about
1562 : * opfamilies and opclass input types. (aminfo and supportinfo are left
1563 : * as zeroes, and are filled on-the-fly when used)
1564 : */
1565 443397 : IndexSupportInitialize(indclass, relation->rd_support,
1566 : relation->rd_opfamily, relation->rd_opcintype,
1567 : amsupport, indnkeyatts);
1568 :
1569 : /*
1570 : * Similarly extract indoption and copy it to the cache entry
1571 : */
1572 443397 : indoptionDatum = fastgetattr(relation->rd_indextuple,
1573 : Anum_pg_index_indoption,
1574 : GetPgIndexDescriptor(),
1575 : &isnull);
1576 : Assert(!isnull);
1577 443397 : indoption = (int2vector *) DatumGetPointer(indoptionDatum);
1578 443397 : memcpy(relation->rd_indoption, indoption->values, indnkeyatts * sizeof(int16));
1579 :
1580 443397 : (void) RelationGetIndexAttOptions(relation, false);
1581 :
1582 : /*
1583 : * expressions, predicate, exclusion caches will be filled later
1584 : */
1585 443393 : relation->rd_indexprs = NIL;
1586 443393 : relation->rd_indpred = NIL;
1587 443393 : relation->rd_exclops = NULL;
1588 443393 : relation->rd_exclprocs = NULL;
1589 443393 : relation->rd_exclstrats = NULL;
1590 443393 : relation->rd_amcache = NULL;
1591 443393 : }
1592 :
1593 : /*
1594 : * IndexSupportInitialize
1595 : * Initializes an index's cached opclass information,
1596 : * given the index's pg_index.indclass entry.
1597 : *
1598 : * Data is returned into *indexSupport, *opFamily, and *opcInType,
1599 : * which are arrays allocated by the caller.
1600 : *
1601 : * The caller also passes maxSupportNumber and maxAttributeNumber, since these
1602 : * indicate the size of the arrays it has allocated --- but in practice these
1603 : * numbers must always match those obtainable from the system catalog entries
1604 : * for the index and access method.
1605 : */
1606 : static void
1607 443397 : IndexSupportInitialize(oidvector *indclass,
1608 : RegProcedure *indexSupport,
1609 : Oid *opFamily,
1610 : Oid *opcInType,
1611 : StrategyNumber maxSupportNumber,
1612 : AttrNumber maxAttributeNumber)
1613 : {
1614 : int attIndex;
1615 :
1616 1202095 : for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++)
1617 : {
1618 : OpClassCacheEnt *opcentry;
1619 :
1620 758698 : if (!OidIsValid(indclass->values[attIndex]))
1621 0 : elog(ERROR, "bogus pg_index tuple");
1622 :
1623 : /* look up the info for this opclass, using a cache */
1624 758698 : opcentry = LookupOpclassInfo(indclass->values[attIndex],
1625 : maxSupportNumber);
1626 :
1627 : /* copy cached data into relcache entry */
1628 758698 : opFamily[attIndex] = opcentry->opcfamily;
1629 758698 : opcInType[attIndex] = opcentry->opcintype;
1630 758698 : if (maxSupportNumber > 0)
1631 758698 : memcpy(&indexSupport[attIndex * maxSupportNumber],
1632 758698 : opcentry->supportProcs,
1633 : maxSupportNumber * sizeof(RegProcedure));
1634 : }
1635 443397 : }
1636 :
1637 : /*
1638 : * LookupOpclassInfo
1639 : *
1640 : * This routine maintains a per-opclass cache of the information needed
1641 : * by IndexSupportInitialize(). This is more efficient than relying on
1642 : * the catalog cache, because we can load all the info about a particular
1643 : * opclass in a single indexscan of pg_amproc.
1644 : *
1645 : * The information from pg_am about expected range of support function
1646 : * numbers is passed in, rather than being looked up, mainly because the
1647 : * caller will have it already.
1648 : *
1649 : * Note there is no provision for flushing the cache. This is OK at the
1650 : * moment because there is no way to ALTER any interesting properties of an
1651 : * existing opclass --- all you can do is drop it, which will result in
1652 : * a useless but harmless dead entry in the cache. To support altering
1653 : * opclass membership (not the same as opfamily membership!), we'd need to
1654 : * be able to flush this cache as well as the contents of relcache entries
1655 : * for indexes.
1656 : */
1657 : static OpClassCacheEnt *
1658 758698 : LookupOpclassInfo(Oid operatorClassOid,
1659 : StrategyNumber numSupport)
1660 : {
1661 : OpClassCacheEnt *opcentry;
1662 : bool found;
1663 : Relation rel;
1664 : SysScanDesc scan;
1665 : ScanKeyData skey[3];
1666 : HeapTuple htup;
1667 : bool indexOK;
1668 :
1669 758698 : if (OpClassCache == NULL)
1670 : {
1671 : /* First time through: initialize the opclass cache */
1672 : HASHCTL ctl;
1673 :
1674 : /* Also make sure CacheMemoryContext exists */
1675 18707 : if (!CacheMemoryContext)
1676 0 : CreateCacheMemoryContext();
1677 :
1678 18707 : ctl.keysize = sizeof(Oid);
1679 18707 : ctl.entrysize = sizeof(OpClassCacheEnt);
1680 18707 : OpClassCache = hash_create("Operator class cache", 64,
1681 : &ctl, HASH_ELEM | HASH_BLOBS);
1682 : }
1683 :
1684 758698 : opcentry = (OpClassCacheEnt *) hash_search(OpClassCache,
1685 : &operatorClassOid,
1686 : HASH_ENTER, &found);
1687 :
1688 758698 : if (!found)
1689 : {
1690 : /* Initialize new entry */
1691 58482 : opcentry->valid = false; /* until known OK */
1692 58482 : opcentry->numSupport = numSupport;
1693 58482 : opcentry->supportProcs = NULL; /* filled below */
1694 : }
1695 : else
1696 : {
1697 : Assert(numSupport == opcentry->numSupport);
1698 : }
1699 :
1700 : /*
1701 : * When aggressively testing cache-flush hazards, we disable the operator
1702 : * class cache and force reloading of the info on each call. This models
1703 : * no real-world behavior, since the cache entries are never invalidated
1704 : * otherwise. However it can be helpful for detecting bugs in the cache
1705 : * loading logic itself, such as reliance on a non-nailed index. Given
1706 : * the limited use-case and the fact that this adds a great deal of
1707 : * expense, we enable it only for high values of debug_discard_caches.
1708 : */
1709 : #ifdef DISCARD_CACHES_ENABLED
1710 : if (debug_discard_caches > 2)
1711 : opcentry->valid = false;
1712 : #endif
1713 :
1714 758698 : if (opcentry->valid)
1715 700216 : return opcentry;
1716 :
1717 : /*
1718 : * Need to fill in new entry. First allocate space, unless we already did
1719 : * so in some previous attempt.
1720 : */
1721 58482 : if (opcentry->supportProcs == NULL && numSupport > 0)
1722 58482 : opcentry->supportProcs = (RegProcedure *)
1723 58482 : MemoryContextAllocZero(CacheMemoryContext,
1724 : numSupport * sizeof(RegProcedure));
1725 :
1726 : /*
1727 : * To avoid infinite recursion during startup, force heap scans if we're
1728 : * looking up info for the opclasses used by the indexes we would like to
1729 : * reference here.
1730 : */
1731 64506 : indexOK = criticalRelcachesBuilt ||
1732 6024 : (operatorClassOid != OID_BTREE_OPS_OID &&
1733 4130 : operatorClassOid != INT2_BTREE_OPS_OID);
1734 :
1735 : /*
1736 : * We have to fetch the pg_opclass row to determine its opfamily and
1737 : * opcintype, which are needed to look up related operators and functions.
1738 : * It'd be convenient to use the syscache here, but that probably doesn't
1739 : * work while bootstrapping.
1740 : */
1741 58482 : ScanKeyInit(&skey[0],
1742 : Anum_pg_opclass_oid,
1743 : BTEqualStrategyNumber, F_OIDEQ,
1744 : ObjectIdGetDatum(operatorClassOid));
1745 58482 : rel = table_open(OperatorClassRelationId, AccessShareLock);
1746 58482 : scan = systable_beginscan(rel, OpclassOidIndexId, indexOK,
1747 : NULL, 1, skey);
1748 :
1749 58482 : if (HeapTupleIsValid(htup = systable_getnext(scan)))
1750 : {
1751 58482 : Form_pg_opclass opclassform = (Form_pg_opclass) GETSTRUCT(htup);
1752 :
1753 58482 : opcentry->opcfamily = opclassform->opcfamily;
1754 58482 : opcentry->opcintype = opclassform->opcintype;
1755 : }
1756 : else
1757 0 : elog(ERROR, "could not find tuple for opclass %u", operatorClassOid);
1758 :
1759 58482 : systable_endscan(scan);
1760 58482 : table_close(rel, AccessShareLock);
1761 :
1762 : /*
1763 : * Scan pg_amproc to obtain support procs for the opclass. We only fetch
1764 : * the default ones (those with lefttype = righttype = opcintype).
1765 : */
1766 58482 : if (numSupport > 0)
1767 : {
1768 58482 : ScanKeyInit(&skey[0],
1769 : Anum_pg_amproc_amprocfamily,
1770 : BTEqualStrategyNumber, F_OIDEQ,
1771 : ObjectIdGetDatum(opcentry->opcfamily));
1772 58482 : ScanKeyInit(&skey[1],
1773 : Anum_pg_amproc_amproclefttype,
1774 : BTEqualStrategyNumber, F_OIDEQ,
1775 : ObjectIdGetDatum(opcentry->opcintype));
1776 58482 : ScanKeyInit(&skey[2],
1777 : Anum_pg_amproc_amprocrighttype,
1778 : BTEqualStrategyNumber, F_OIDEQ,
1779 : ObjectIdGetDatum(opcentry->opcintype));
1780 58482 : rel = table_open(AccessMethodProcedureRelationId, AccessShareLock);
1781 58482 : scan = systable_beginscan(rel, AccessMethodProcedureIndexId, indexOK,
1782 : NULL, 3, skey);
1783 :
1784 279684 : while (HeapTupleIsValid(htup = systable_getnext(scan)))
1785 : {
1786 221202 : Form_pg_amproc amprocform = (Form_pg_amproc) GETSTRUCT(htup);
1787 :
1788 221202 : if (amprocform->amprocnum <= 0 ||
1789 221202 : (StrategyNumber) amprocform->amprocnum > numSupport)
1790 0 : elog(ERROR, "invalid amproc number %d for opclass %u",
1791 : amprocform->amprocnum, operatorClassOid);
1792 :
1793 221202 : opcentry->supportProcs[amprocform->amprocnum - 1] =
1794 221202 : amprocform->amproc;
1795 : }
1796 :
1797 58482 : systable_endscan(scan);
1798 58482 : table_close(rel, AccessShareLock);
1799 : }
1800 :
1801 58482 : opcentry->valid = true;
1802 58482 : return opcentry;
1803 : }
1804 :
1805 : /*
1806 : * Fill in the TableAmRoutine for a relation
1807 : *
1808 : * relation's rd_amhandler must be valid already.
1809 : */
1810 : static void
1811 1547058 : InitTableAmRoutine(Relation relation)
1812 : {
1813 1547058 : relation->rd_tableam = GetTableAmRoutine(relation->rd_amhandler);
1814 1547058 : }
1815 :
1816 : /*
1817 : * Initialize table access method support for a table like relation
1818 : */
1819 : void
1820 1547058 : RelationInitTableAccessMethod(Relation relation)
1821 : {
1822 : HeapTuple tuple;
1823 : Form_pg_am aform;
1824 :
1825 1547058 : if (relation->rd_rel->relkind == RELKIND_SEQUENCE)
1826 : {
1827 : /*
1828 : * Sequences are currently accessed like heap tables, but it doesn't
1829 : * seem prudent to show that in the catalog. So just overwrite it
1830 : * here.
1831 : */
1832 : Assert(relation->rd_rel->relam == InvalidOid);
1833 5004 : relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
1834 : }
1835 1542054 : else if (IsCatalogRelation(relation))
1836 : {
1837 : /*
1838 : * Avoid doing a syscache lookup for catalog tables.
1839 : */
1840 : Assert(relation->rd_rel->relam == HEAP_TABLE_AM_OID);
1841 1225618 : relation->rd_amhandler = F_HEAP_TABLEAM_HANDLER;
1842 : }
1843 : else
1844 : {
1845 : /*
1846 : * Look up the table access method, save the OID of its handler
1847 : * function.
1848 : */
1849 : Assert(relation->rd_rel->relam != InvalidOid);
1850 316436 : tuple = SearchSysCache1(AMOID,
1851 316436 : ObjectIdGetDatum(relation->rd_rel->relam));
1852 316436 : if (!HeapTupleIsValid(tuple))
1853 0 : elog(ERROR, "cache lookup failed for access method %u",
1854 : relation->rd_rel->relam);
1855 316436 : aform = (Form_pg_am) GETSTRUCT(tuple);
1856 316436 : relation->rd_amhandler = aform->amhandler;
1857 316436 : ReleaseSysCache(tuple);
1858 : }
1859 :
1860 : /*
1861 : * Now we can fetch the table AM's API struct
1862 : */
1863 1547058 : InitTableAmRoutine(relation);
1864 1547058 : }
1865 :
1866 : /*
1867 : * formrdesc
1868 : *
1869 : * This is a special cut-down version of RelationBuildDesc(),
1870 : * used while initializing the relcache.
1871 : * The relation descriptor is built just from the supplied parameters,
1872 : * without actually looking at any system table entries. We cheat
1873 : * quite a lot since we only need to work for a few basic system
1874 : * catalogs.
1875 : *
1876 : * The catalogs this is used for can't have constraints (except attnotnull),
1877 : * default values, rules, or triggers, since we don't cope with any of that.
1878 : * (Well, actually, this only matters for properties that need to be valid
1879 : * during bootstrap or before RelationCacheInitializePhase3 runs, and none of
1880 : * these properties matter then...)
1881 : *
1882 : * NOTE: we assume we are already switched into CacheMemoryContext.
1883 : */
1884 : static void
1885 20591 : formrdesc(const char *relationName, Oid relationReltype,
1886 : bool isshared,
1887 : int natts, const FormData_pg_attribute *attrs)
1888 : {
1889 : Relation relation;
1890 : int i;
1891 : bool has_not_null;
1892 :
1893 : /*
1894 : * allocate new relation desc, clear all fields of reldesc
1895 : */
1896 20591 : relation = palloc0_object(RelationData);
1897 :
1898 : /* make sure relation is marked as having no open file yet */
1899 20591 : relation->rd_smgr = NULL;
1900 :
1901 : /*
1902 : * initialize reference count: 1 because it is nailed in cache
1903 : */
1904 20591 : relation->rd_refcnt = 1;
1905 :
1906 : /*
1907 : * all entries built with this routine are nailed-in-cache; none are for
1908 : * new or temp relations.
1909 : */
1910 20591 : relation->rd_isnailed = true;
1911 20591 : relation->rd_createSubid = InvalidSubTransactionId;
1912 20591 : relation->rd_newRelfilelocatorSubid = InvalidSubTransactionId;
1913 20591 : relation->rd_firstRelfilelocatorSubid = InvalidSubTransactionId;
1914 20591 : relation->rd_droppedSubid = InvalidSubTransactionId;
1915 20591 : relation->rd_backend = INVALID_PROC_NUMBER;
1916 20591 : relation->rd_islocaltemp = false;
1917 :
1918 : /*
1919 : * initialize relation tuple form
1920 : *
1921 : * The data we insert here is pretty incomplete/bogus, but it'll serve to
1922 : * get us launched. RelationCacheInitializePhase3() will read the real
1923 : * data from pg_class and replace what we've done here. Note in
1924 : * particular that relowner is left as zero; this cues
1925 : * RelationCacheInitializePhase3 that the real data isn't there yet.
1926 : */
1927 20591 : relation->rd_rel = (Form_pg_class) palloc0(CLASS_TUPLE_SIZE);
1928 :
1929 20591 : namestrcpy(&relation->rd_rel->relname, relationName);
1930 20591 : relation->rd_rel->relnamespace = PG_CATALOG_NAMESPACE;
1931 20591 : relation->rd_rel->reltype = relationReltype;
1932 :
1933 : /*
1934 : * It's important to distinguish between shared and non-shared relations,
1935 : * even at bootstrap time, to make sure we know where they are stored.
1936 : */
1937 20591 : relation->rd_rel->relisshared = isshared;
1938 20591 : if (isshared)
1939 13015 : relation->rd_rel->reltablespace = GLOBALTABLESPACE_OID;
1940 :
1941 : /* formrdesc is used only for permanent relations */
1942 20591 : relation->rd_rel->relpersistence = RELPERSISTENCE_PERMANENT;
1943 :
1944 : /* ... and they're always populated, too */
1945 20591 : relation->rd_rel->relispopulated = true;
1946 :
1947 20591 : relation->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
1948 20591 : relation->rd_rel->relpages = 0;
1949 20591 : relation->rd_rel->reltuples = -1;
1950 20591 : relation->rd_rel->relallvisible = 0;
1951 20591 : relation->rd_rel->relallfrozen = 0;
1952 20591 : relation->rd_rel->relkind = RELKIND_RELATION;
1953 20591 : relation->rd_rel->relnatts = (int16) natts;
1954 :
1955 : /*
1956 : * initialize attribute tuple form
1957 : *
1958 : * Unlike the case with the relation tuple, this data had better be right
1959 : * because it will never be replaced. The data comes from
1960 : * src/include/catalog/ headers via genbki.pl.
1961 : */
1962 20591 : relation->rd_att = CreateTemplateTupleDesc(natts);
1963 20591 : relation->rd_att->tdrefcount = 1; /* mark as refcounted */
1964 :
1965 20591 : relation->rd_att->tdtypeid = relationReltype;
1966 20591 : relation->rd_att->tdtypmod = -1; /* just to be sure */
1967 :
1968 : /*
1969 : * initialize tuple desc info
1970 : */
1971 20591 : has_not_null = false;
1972 416357 : for (i = 0; i < natts; i++)
1973 : {
1974 791532 : memcpy(TupleDescAttr(relation->rd_att, i),
1975 395766 : &attrs[i],
1976 : ATTRIBUTE_FIXED_PART_SIZE);
1977 395766 : has_not_null |= attrs[i].attnotnull;
1978 :
1979 395766 : populate_compact_attribute(relation->rd_att, i);
1980 : }
1981 :
1982 20591 : TupleDescFinalize(relation->rd_att);
1983 :
1984 : /* mark not-null status */
1985 20591 : if (has_not_null)
1986 : {
1987 20591 : TupleConstr *constr = palloc0_object(TupleConstr);
1988 :
1989 20591 : constr->has_not_null = true;
1990 20591 : relation->rd_att->constr = constr;
1991 : }
1992 :
1993 : /*
1994 : * initialize relation id from info in att array (my, this is ugly)
1995 : */
1996 20591 : RelationGetRelid(relation) = TupleDescAttr(relation->rd_att, 0)->attrelid;
1997 :
1998 : /*
1999 : * All relations made with formrdesc are mapped. This is necessarily so
2000 : * because there is no other way to know what filenumber they currently
2001 : * have. In bootstrap mode, add them to the initial relation mapper data,
2002 : * specifying that the initial filenumber is the same as the OID.
2003 : */
2004 20591 : relation->rd_rel->relfilenode = InvalidRelFileNumber;
2005 20591 : if (IsBootstrapProcessingMode())
2006 228 : RelationMapUpdateMap(RelationGetRelid(relation),
2007 : RelationGetRelid(relation),
2008 : isshared, true);
2009 :
2010 : /*
2011 : * initialize the relation lock manager information
2012 : */
2013 20591 : RelationInitLockInfo(relation); /* see lmgr.c */
2014 :
2015 : /*
2016 : * initialize physical addressing information for the relation
2017 : */
2018 20591 : RelationInitPhysicalAddr(relation);
2019 :
2020 : /*
2021 : * initialize the table am handler
2022 : */
2023 20591 : relation->rd_rel->relam = HEAP_TABLE_AM_OID;
2024 20591 : relation->rd_tableam = GetHeapamTableAmRoutine();
2025 :
2026 : /*
2027 : * initialize the rel-has-index flag, using hardwired knowledge
2028 : */
2029 20591 : if (IsBootstrapProcessingMode())
2030 : {
2031 : /* In bootstrap mode, we have no indexes */
2032 228 : relation->rd_rel->relhasindex = false;
2033 : }
2034 : else
2035 : {
2036 : /* Otherwise, all the rels formrdesc is used for have indexes */
2037 20363 : relation->rd_rel->relhasindex = true;
2038 : }
2039 :
2040 : /*
2041 : * add new reldesc to relcache
2042 : */
2043 20591 : RelationCacheInsert(relation, false);
2044 :
2045 : /* It's fully valid */
2046 20591 : relation->rd_isvalid = true;
2047 20591 : }
2048 :
2049 : #ifdef USE_ASSERT_CHECKING
2050 : /*
2051 : * AssertCouldGetRelation
2052 : *
2053 : * Check safety of calling RelationIdGetRelation().
2054 : *
2055 : * In code that reads catalogs in the event of a cache miss, call this
2056 : * before checking the cache.
2057 : */
2058 : void
2059 : AssertCouldGetRelation(void)
2060 : {
2061 : Assert(IsTransactionState());
2062 : AssertBufferLocksPermitCatalogRead();
2063 : }
2064 : #endif
2065 :
2066 :
2067 : /* ----------------------------------------------------------------
2068 : * Relation Descriptor Lookup Interface
2069 : * ----------------------------------------------------------------
2070 : */
2071 :
2072 : /*
2073 : * RelationIdGetRelation
2074 : *
2075 : * Lookup a reldesc by OID; make one if not already in cache.
2076 : *
2077 : * Returns NULL if no pg_class row could be found for the given relid
2078 : * (suggesting we are trying to access a just-deleted relation).
2079 : * Any other error is reported via elog.
2080 : *
2081 : * NB: caller should already have at least AccessShareLock on the
2082 : * relation ID, else there are nasty race conditions.
2083 : *
2084 : * NB: relation ref count is incremented, or set to 1 if new entry.
2085 : * Caller should eventually decrement count. (Usually,
2086 : * that happens by calling RelationClose().)
2087 : */
2088 : Relation
2089 28737096 : RelationIdGetRelation(Oid relationId)
2090 : {
2091 : Relation rd;
2092 :
2093 28737096 : AssertCouldGetRelation();
2094 :
2095 : /*
2096 : * first try to find reldesc in the cache
2097 : */
2098 28737096 : RelationIdCacheLookup(relationId, rd);
2099 :
2100 28737096 : if (RelationIsValid(rd))
2101 : {
2102 : /* return NULL for dropped relations */
2103 27967987 : if (rd->rd_droppedSubid != InvalidSubTransactionId)
2104 : {
2105 : Assert(!rd->rd_isvalid);
2106 2 : return NULL;
2107 : }
2108 :
2109 27967985 : RelationIncrementReferenceCount(rd);
2110 : /* revalidate cache entry if necessary */
2111 27967985 : if (!rd->rd_isvalid)
2112 : {
2113 109321 : RelationRebuildRelation(rd);
2114 :
2115 : /*
2116 : * Normally entries need to be valid here, but before the relcache
2117 : * has been initialized, not enough infrastructure exists to
2118 : * perform pg_class lookups. The structure of such entries doesn't
2119 : * change, but we still want to update the rd_rel entry. So
2120 : * rd_isvalid = false is left in place for a later lookup.
2121 : */
2122 : Assert(rd->rd_isvalid ||
2123 : (rd->rd_isnailed && !criticalRelcachesBuilt));
2124 : }
2125 27967979 : return rd;
2126 : }
2127 :
2128 : /*
2129 : * no reldesc in the cache, so have RelationBuildDesc() build one and add
2130 : * it.
2131 : */
2132 769109 : rd = RelationBuildDesc(relationId, true);
2133 769109 : if (RelationIsValid(rd))
2134 769103 : RelationIncrementReferenceCount(rd);
2135 769109 : return rd;
2136 : }
2137 :
2138 : /*
2139 : * Returns a schema-qualified name of the relation.
2140 : */
2141 : char *
2142 81 : RelationGetQualifiedRelationName(Relation rel)
2143 : {
2144 162 : return get_qualified_objname(RelationGetNamespace(rel),
2145 81 : RelationGetRelationName(rel));
2146 : }
2147 :
2148 : /* ----------------------------------------------------------------
2149 : * cache invalidation support routines
2150 : * ----------------------------------------------------------------
2151 : */
2152 :
2153 : /* ResourceOwner callbacks to track relcache references */
2154 : static void ResOwnerReleaseRelation(Datum res);
2155 : static char *ResOwnerPrintRelCache(Datum res);
2156 :
2157 : static const ResourceOwnerDesc relref_resowner_desc =
2158 : {
2159 : .name = "relcache reference",
2160 : .release_phase = RESOURCE_RELEASE_BEFORE_LOCKS,
2161 : .release_priority = RELEASE_PRIO_RELCACHE_REFS,
2162 : .ReleaseResource = ResOwnerReleaseRelation,
2163 : .DebugPrint = ResOwnerPrintRelCache
2164 : };
2165 :
2166 : /* Convenience wrappers over ResourceOwnerRemember/Forget */
2167 : static inline void
2168 42171255 : ResourceOwnerRememberRelationRef(ResourceOwner owner, Relation rel)
2169 : {
2170 42171255 : ResourceOwnerRemember(owner, PointerGetDatum(rel), &relref_resowner_desc);
2171 42171255 : }
2172 : static inline void
2173 42138918 : ResourceOwnerForgetRelationRef(ResourceOwner owner, Relation rel)
2174 : {
2175 42138918 : ResourceOwnerForget(owner, PointerGetDatum(rel), &relref_resowner_desc);
2176 42138918 : }
2177 :
2178 : /*
2179 : * RelationIncrementReferenceCount
2180 : * Increments relation reference count.
2181 : *
2182 : * Note: bootstrap mode has its own weird ideas about relation refcount
2183 : * behavior; we ought to fix it someday, but for now, just disable
2184 : * reference count ownership tracking in bootstrap mode.
2185 : */
2186 : void
2187 42517758 : RelationIncrementReferenceCount(Relation rel)
2188 : {
2189 42517758 : ResourceOwnerEnlarge(CurrentResourceOwner);
2190 42517758 : rel->rd_refcnt += 1;
2191 42517758 : if (!IsBootstrapProcessingMode())
2192 42171255 : ResourceOwnerRememberRelationRef(CurrentResourceOwner, rel);
2193 42517758 : }
2194 :
2195 : /*
2196 : * RelationDecrementReferenceCount
2197 : * Decrements relation reference count.
2198 : */
2199 : void
2200 42485421 : RelationDecrementReferenceCount(Relation rel)
2201 : {
2202 : Assert(rel->rd_refcnt > 0);
2203 42485421 : rel->rd_refcnt -= 1;
2204 42485421 : if (!IsBootstrapProcessingMode())
2205 42138918 : ResourceOwnerForgetRelationRef(CurrentResourceOwner, rel);
2206 42485421 : }
2207 :
2208 : /*
2209 : * RelationClose - close an open relation
2210 : *
2211 : * Actually, we just decrement the refcount.
2212 : *
2213 : * NOTE: if compiled with -DRELCACHE_FORCE_RELEASE then relcache entries
2214 : * will be freed as soon as their refcount goes to zero. In combination
2215 : * with aset.c's CLOBBER_FREED_MEMORY option, this provides a good test
2216 : * to catch references to already-released relcache entries. It slows
2217 : * things down quite a bit, however.
2218 : */
2219 : void
2220 28800239 : RelationClose(Relation relation)
2221 : {
2222 : /* Note: no locking manipulations needed */
2223 28800239 : RelationDecrementReferenceCount(relation);
2224 :
2225 28800239 : RelationCloseCleanup(relation);
2226 28800239 : }
2227 :
2228 : static void
2229 28832576 : RelationCloseCleanup(Relation relation)
2230 : {
2231 : /*
2232 : * If the relation is no longer open in this session, we can clean up any
2233 : * stale partition descriptors it has. This is unlikely, so check to see
2234 : * if there are child contexts before expending a call to mcxt.c.
2235 : */
2236 28832576 : if (RelationHasReferenceCountZero(relation))
2237 : {
2238 16183802 : if (relation->rd_pdcxt != NULL &&
2239 75127 : relation->rd_pdcxt->firstchild != NULL)
2240 3007 : MemoryContextDeleteChildren(relation->rd_pdcxt);
2241 :
2242 16183802 : if (relation->rd_pddcxt != NULL &&
2243 54 : relation->rd_pddcxt->firstchild != NULL)
2244 0 : MemoryContextDeleteChildren(relation->rd_pddcxt);
2245 : }
2246 :
2247 : #ifdef RELCACHE_FORCE_RELEASE
2248 : if (RelationHasReferenceCountZero(relation) &&
2249 : relation->rd_createSubid == InvalidSubTransactionId &&
2250 : relation->rd_firstRelfilelocatorSubid == InvalidSubTransactionId)
2251 : RelationClearRelation(relation);
2252 : #endif
2253 28832576 : }
2254 :
2255 : /*
2256 : * RelationReloadIndexInfo - reload minimal information for an open index
2257 : *
2258 : * This function is used only for indexes. A relcache inval on an index
2259 : * can mean that its pg_class or pg_index row changed. There are only
2260 : * very limited changes that are allowed to an existing index's schema,
2261 : * so we can update the relcache entry without a complete rebuild; which
2262 : * is fortunate because we can't rebuild an index entry that is "nailed"
2263 : * and/or in active use. We support full replacement of the pg_class row,
2264 : * as well as updates of a few simple fields of the pg_index row.
2265 : *
2266 : * We assume that at the time we are called, we have at least AccessShareLock
2267 : * on the target index.
2268 : *
2269 : * If the target index is an index on pg_class or pg_index, we'd better have
2270 : * previously gotten at least AccessShareLock on its underlying catalog,
2271 : * else we are at risk of deadlock against someone trying to exclusive-lock
2272 : * the heap and index in that order. This is ensured in current usage by
2273 : * only applying this to indexes being opened or having positive refcount.
2274 : */
2275 : static void
2276 75606 : RelationReloadIndexInfo(Relation relation)
2277 : {
2278 : bool indexOK;
2279 : HeapTuple pg_class_tuple;
2280 : Form_pg_class relp;
2281 :
2282 : /* Should be called only for invalidated, live indexes */
2283 : Assert((relation->rd_rel->relkind == RELKIND_INDEX ||
2284 : relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) &&
2285 : !relation->rd_isvalid &&
2286 : relation->rd_droppedSubid == InvalidSubTransactionId);
2287 :
2288 : /*
2289 : * If it's a shared index, we might be called before backend startup has
2290 : * finished selecting a database, in which case we have no way to read
2291 : * pg_class yet. However, a shared index can never have any significant
2292 : * schema updates, so it's okay to mostly ignore the invalidation signal.
2293 : * Its physical relfilenumber might've changed, but that's all. Update
2294 : * the physical relfilenumber, mark it valid and return without doing
2295 : * anything more.
2296 : */
2297 75606 : if (relation->rd_rel->relisshared && !criticalRelcachesBuilt)
2298 : {
2299 0 : RelationInitPhysicalAddr(relation);
2300 0 : relation->rd_isvalid = true;
2301 0 : return;
2302 : }
2303 :
2304 : /*
2305 : * Read the pg_class row
2306 : *
2307 : * Don't try to use an indexscan of pg_class_oid_index to reload the info
2308 : * for pg_class_oid_index ...
2309 : */
2310 75606 : indexOK = (RelationGetRelid(relation) != ClassOidIndexId);
2311 75606 : pg_class_tuple = ScanPgRelation(RelationGetRelid(relation), indexOK, false);
2312 75603 : if (!HeapTupleIsValid(pg_class_tuple))
2313 0 : elog(ERROR, "could not find pg_class tuple for index %u",
2314 : RelationGetRelid(relation));
2315 75603 : relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
2316 75603 : memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);
2317 : /* Reload reloptions in case they changed */
2318 75603 : if (relation->rd_options)
2319 651 : pfree(relation->rd_options);
2320 75603 : RelationParseRelOptions(relation, pg_class_tuple);
2321 : /* done with pg_class tuple */
2322 75603 : heap_freetuple(pg_class_tuple);
2323 : /* We must recalculate physical address in case it changed */
2324 75603 : RelationInitPhysicalAddr(relation);
2325 :
2326 : /*
2327 : * For a non-system index, there are fields of the pg_index row that are
2328 : * allowed to change, so re-read that row and update the relcache entry.
2329 : * Most of the info derived from pg_index (such as support function lookup
2330 : * info) cannot change, and indeed the whole point of this routine is to
2331 : * update the relcache entry without clobbering that data; so wholesale
2332 : * replacement is not appropriate.
2333 : */
2334 75603 : if (!IsSystemRelation(relation))
2335 : {
2336 : HeapTuple tuple;
2337 : Form_pg_index index;
2338 :
2339 29346 : tuple = SearchSysCache1(INDEXRELID,
2340 : ObjectIdGetDatum(RelationGetRelid(relation)));
2341 29346 : if (!HeapTupleIsValid(tuple))
2342 0 : elog(ERROR, "cache lookup failed for index %u",
2343 : RelationGetRelid(relation));
2344 29346 : index = (Form_pg_index) GETSTRUCT(tuple);
2345 :
2346 : /*
2347 : * Basically, let's just copy all the bool fields. There are one or
2348 : * two of these that can't actually change in the current code, but
2349 : * it's not worth it to track exactly which ones they are. None of
2350 : * the array fields are allowed to change, though.
2351 : */
2352 29346 : relation->rd_index->indisunique = index->indisunique;
2353 29346 : relation->rd_index->indnullsnotdistinct = index->indnullsnotdistinct;
2354 29346 : relation->rd_index->indisprimary = index->indisprimary;
2355 29346 : relation->rd_index->indisexclusion = index->indisexclusion;
2356 29346 : relation->rd_index->indimmediate = index->indimmediate;
2357 29346 : relation->rd_index->indisclustered = index->indisclustered;
2358 29346 : relation->rd_index->indisvalid = index->indisvalid;
2359 29346 : relation->rd_index->indcheckxmin = index->indcheckxmin;
2360 29346 : relation->rd_index->indisready = index->indisready;
2361 29346 : relation->rd_index->indislive = index->indislive;
2362 29346 : relation->rd_index->indisreplident = index->indisreplident;
2363 :
2364 : /* Copy xmin too, as that is needed to make sense of indcheckxmin */
2365 29346 : HeapTupleHeaderSetXmin(relation->rd_indextuple->t_data,
2366 29346 : HeapTupleHeaderGetXmin(tuple->t_data));
2367 :
2368 29346 : ReleaseSysCache(tuple);
2369 : }
2370 :
2371 : /* Okay, now it's valid again */
2372 75603 : relation->rd_isvalid = true;
2373 : }
2374 :
2375 : /*
2376 : * RelationReloadNailed - reload minimal information for nailed relations.
2377 : *
2378 : * The structure of a nailed relation can never change (which is good, because
2379 : * we rely on knowing their structure to be able to read catalog content). But
2380 : * some parts, e.g. pg_class.relfrozenxid, are still important to have
2381 : * accurate content for. Therefore those need to be reloaded after the arrival
2382 : * of invalidations.
2383 : */
2384 : static void
2385 98229 : RelationReloadNailed(Relation relation)
2386 : {
2387 : /* Should be called only for invalidated, nailed relations */
2388 : Assert(!relation->rd_isvalid);
2389 : Assert(relation->rd_isnailed);
2390 : /* nailed indexes are handled by RelationReloadIndexInfo() */
2391 : Assert(relation->rd_rel->relkind == RELKIND_RELATION);
2392 98229 : AssertCouldGetRelation();
2393 :
2394 : /*
2395 : * Redo RelationInitPhysicalAddr in case it is a mapped relation whose
2396 : * mapping changed.
2397 : */
2398 98229 : RelationInitPhysicalAddr(relation);
2399 :
2400 : /*
2401 : * Reload a non-index entry. We can't easily do so if relcaches aren't
2402 : * yet built, but that's fine because at that stage the attributes that
2403 : * need to be current (like relfrozenxid) aren't yet accessed. To ensure
2404 : * the entry will later be revalidated, we leave it in invalid state, but
2405 : * allow use (cf. RelationIdGetRelation()).
2406 : */
2407 98229 : if (criticalRelcachesBuilt)
2408 : {
2409 : HeapTuple pg_class_tuple;
2410 : Form_pg_class relp;
2411 :
2412 : /*
2413 : * NB: Mark the entry as valid before starting to scan, to avoid
2414 : * self-recursion when re-building pg_class.
2415 : */
2416 19818 : relation->rd_isvalid = true;
2417 :
2418 19818 : pg_class_tuple = ScanPgRelation(RelationGetRelid(relation),
2419 : true, false);
2420 19815 : relp = (Form_pg_class) GETSTRUCT(pg_class_tuple);
2421 19815 : memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE);
2422 19815 : heap_freetuple(pg_class_tuple);
2423 :
2424 : /*
2425 : * Again mark as valid, to protect against concurrently arriving
2426 : * invalidations.
2427 : */
2428 19815 : relation->rd_isvalid = true;
2429 : }
2430 98226 : }
2431 :
2432 : /*
2433 : * RelationDestroyRelation
2434 : *
2435 : * Physically delete a relation cache entry and all subsidiary data.
2436 : * Caller must already have unhooked the entry from the hash table.
2437 : */
2438 : static void
2439 864419 : RelationDestroyRelation(Relation relation, bool remember_tupdesc)
2440 : {
2441 : Assert(RelationHasReferenceCountZero(relation));
2442 :
2443 : /*
2444 : * Make sure smgr and lower levels close the relation's files, if they
2445 : * weren't closed already. (This was probably done by caller, but let's
2446 : * just be real sure.)
2447 : */
2448 864419 : RelationCloseSmgr(relation);
2449 :
2450 : /* break mutual link with stats entry */
2451 864419 : pgstat_unlink_relation(relation);
2452 :
2453 : /*
2454 : * Free all the subsidiary data structures of the relcache entry, then the
2455 : * entry itself.
2456 : */
2457 864419 : if (relation->rd_rel)
2458 864419 : pfree(relation->rd_rel);
2459 : /* can't use DecrTupleDescRefCount here */
2460 : Assert(relation->rd_att->tdrefcount > 0);
2461 864419 : if (--relation->rd_att->tdrefcount == 0)
2462 : {
2463 : /*
2464 : * If we Rebuilt a relcache entry during a transaction then its
2465 : * possible we did that because the TupDesc changed as the result of
2466 : * an ALTER TABLE that ran at less than AccessExclusiveLock. It's
2467 : * possible someone copied that TupDesc, in which case the copy would
2468 : * point to free'd memory. So if we rebuild an entry we keep the
2469 : * TupDesc around until end of transaction, to be safe.
2470 : */
2471 862142 : if (remember_tupdesc)
2472 15911 : RememberToFreeTupleDescAtEOX(relation->rd_att);
2473 : else
2474 846231 : FreeTupleDesc(relation->rd_att);
2475 : }
2476 864419 : FreeTriggerDesc(relation->trigdesc);
2477 864419 : list_free_deep(relation->rd_fkeylist);
2478 864419 : list_free(relation->rd_indexlist);
2479 864419 : list_free(relation->rd_statlist);
2480 864419 : bms_free(relation->rd_keyattr);
2481 864419 : bms_free(relation->rd_pkattr);
2482 864419 : bms_free(relation->rd_idattr);
2483 864419 : bms_free(relation->rd_hotblockingattr);
2484 864419 : bms_free(relation->rd_summarizedattr);
2485 864419 : if (relation->rd_pubdesc)
2486 5084 : pfree(relation->rd_pubdesc);
2487 864419 : if (relation->rd_options)
2488 7964 : pfree(relation->rd_options);
2489 864419 : if (relation->rd_indextuple)
2490 253157 : pfree(relation->rd_indextuple);
2491 864419 : if (relation->rd_amcache)
2492 0 : pfree(relation->rd_amcache);
2493 864419 : if (relation->rd_fdwroutine)
2494 161 : pfree(relation->rd_fdwroutine);
2495 864419 : if (relation->rd_indexcxt)
2496 253157 : MemoryContextDelete(relation->rd_indexcxt);
2497 864419 : if (relation->rd_rulescxt)
2498 16672 : MemoryContextDelete(relation->rd_rulescxt);
2499 864419 : if (relation->rd_rsdesc)
2500 1697 : MemoryContextDelete(relation->rd_rsdesc->rscxt);
2501 864419 : if (relation->rd_partkeycxt)
2502 12699 : MemoryContextDelete(relation->rd_partkeycxt);
2503 864419 : if (relation->rd_pdcxt)
2504 12345 : MemoryContextDelete(relation->rd_pdcxt);
2505 864419 : if (relation->rd_pddcxt)
2506 30 : MemoryContextDelete(relation->rd_pddcxt);
2507 864419 : if (relation->rd_partcheckcxt)
2508 2172 : MemoryContextDelete(relation->rd_partcheckcxt);
2509 864419 : pfree(relation);
2510 864419 : }
2511 :
2512 : /*
2513 : * RelationInvalidateRelation - mark a relation cache entry as invalid
2514 : *
2515 : * An entry that's marked as invalid will be reloaded on next access.
2516 : */
2517 : static void
2518 1126795 : RelationInvalidateRelation(Relation relation)
2519 : {
2520 : /*
2521 : * Make sure smgr and lower levels close the relation's files, if they
2522 : * weren't closed already. If the relation is not getting deleted, the
2523 : * next smgr access should reopen the files automatically. This ensures
2524 : * that the low-level file access state is updated after, say, a vacuum
2525 : * truncation.
2526 : */
2527 1126795 : RelationCloseSmgr(relation);
2528 :
2529 : /* Free AM cached data, if any */
2530 1126795 : if (relation->rd_amcache)
2531 46064 : pfree(relation->rd_amcache);
2532 1126795 : relation->rd_amcache = NULL;
2533 :
2534 1126795 : relation->rd_isvalid = false;
2535 1126795 : }
2536 :
2537 : /*
2538 : * RelationClearRelation - physically blow away a relation cache entry
2539 : *
2540 : * The caller must ensure that the entry is no longer needed, i.e. its
2541 : * reference count is zero. Also, the rel or its storage must not be created
2542 : * in the current transaction (rd_createSubid and rd_firstRelfilelocatorSubid
2543 : * must not be set).
2544 : */
2545 : static void
2546 581435 : RelationClearRelation(Relation relation)
2547 : {
2548 : Assert(RelationHasReferenceCountZero(relation));
2549 : Assert(!relation->rd_isnailed);
2550 :
2551 : /*
2552 : * Relations created in the same transaction must never be removed, see
2553 : * RelationFlushRelation.
2554 : */
2555 : Assert(relation->rd_createSubid == InvalidSubTransactionId);
2556 : Assert(relation->rd_firstRelfilelocatorSubid == InvalidSubTransactionId);
2557 : Assert(relation->rd_droppedSubid == InvalidSubTransactionId);
2558 :
2559 : /* first mark it as invalid */
2560 581435 : RelationInvalidateRelation(relation);
2561 :
2562 : /* Remove it from the hash table */
2563 581435 : RelationCacheDelete(relation);
2564 :
2565 : /* And release storage */
2566 581435 : RelationDestroyRelation(relation, false);
2567 581435 : }
2568 :
2569 : /*
2570 : * RelationRebuildRelation - rebuild a relation cache entry in place
2571 : *
2572 : * Reset and rebuild a relation cache entry from scratch (that is, from
2573 : * catalog entries). This is used when we are notified of a change to an open
2574 : * relation (one with refcount > 0). The entry is reconstructed without
2575 : * moving the physical RelationData record, so that the refcount holder's
2576 : * pointer is still valid.
2577 : *
2578 : * NB: when rebuilding, we'd better hold some lock on the relation, else the
2579 : * catalog data we need to read could be changing under us. Also, a rel to be
2580 : * rebuilt had better have refcnt > 0. This is because a sinval reset could
2581 : * happen while we're accessing the catalogs, and the rel would get blown away
2582 : * underneath us by RelationCacheInvalidate if it has zero refcnt.
2583 : */
2584 : static void
2585 456814 : RelationRebuildRelation(Relation relation)
2586 : {
2587 : Assert(!RelationHasReferenceCountZero(relation));
2588 456814 : AssertCouldGetRelation();
2589 : /* there is no reason to ever rebuild a dropped relation */
2590 : Assert(relation->rd_droppedSubid == InvalidSubTransactionId);
2591 :
2592 : /* Close and mark it as invalid until we've finished the rebuild */
2593 456814 : RelationInvalidateRelation(relation);
2594 :
2595 : /*
2596 : * Indexes only have a limited number of possible schema changes, and we
2597 : * don't want to use the full-blown procedure because it's a headache for
2598 : * indexes that reload itself depends on.
2599 : *
2600 : * As an exception, use the full procedure if the index access info hasn't
2601 : * been initialized yet. Index creation relies on that: it first builds
2602 : * the relcache entry with RelationBuildLocalRelation(), creates the
2603 : * pg_index tuple only after that, and then relies on
2604 : * CommandCounterIncrement to load the pg_index contents.
2605 : */
2606 456814 : if ((relation->rd_rel->relkind == RELKIND_INDEX ||
2607 363826 : relation->rd_rel->relkind == RELKIND_PARTITIONED_INDEX) &&
2608 97106 : relation->rd_indexcxt != NULL)
2609 : {
2610 75606 : RelationReloadIndexInfo(relation);
2611 75603 : return;
2612 : }
2613 : /* Nailed relations are handled separately. */
2614 381208 : else if (relation->rd_isnailed)
2615 : {
2616 98229 : RelationReloadNailed(relation);
2617 98226 : return;
2618 : }
2619 : else
2620 : {
2621 : /*
2622 : * Our strategy for rebuilding an open relcache entry is to build a
2623 : * new entry from scratch, swap its contents with the old entry, and
2624 : * finally delete the new entry (along with any infrastructure swapped
2625 : * over from the old entry). This is to avoid trouble in case an
2626 : * error causes us to lose control partway through. The old entry
2627 : * will still be marked !rd_isvalid, so we'll try to rebuild it again
2628 : * on next access. Meanwhile it's not any less valid than it was
2629 : * before, so any code that might expect to continue accessing it
2630 : * isn't hurt by the rebuild failure. (Consider for example a
2631 : * subtransaction that ALTERs a table and then gets canceled partway
2632 : * through the cache entry rebuild. The outer transaction should
2633 : * still see the not-modified cache entry as valid.) The worst
2634 : * consequence of an error is leaking the necessarily-unreferenced new
2635 : * entry, and this shouldn't happen often enough for that to be a big
2636 : * problem.
2637 : *
2638 : * When rebuilding an open relcache entry, we must preserve ref count,
2639 : * rd_*Subid, and rd_toastoid state. Also attempt to preserve the
2640 : * pg_class entry (rd_rel), tupledesc, rewrite-rule, partition key,
2641 : * and partition descriptor substructures in place, because various
2642 : * places assume that these structures won't move while they are
2643 : * working with an open relcache entry. (Note: the refcount
2644 : * mechanism for tupledescs might someday allow us to remove this hack
2645 : * for the tupledesc.)
2646 : *
2647 : * Note that this process does not touch CurrentResourceOwner; which
2648 : * is good because whatever ref counts the entry may have do not
2649 : * necessarily belong to that resource owner.
2650 : */
2651 : Relation newrel;
2652 282979 : Oid save_relid = RelationGetRelid(relation);
2653 : bool keep_tupdesc;
2654 : bool keep_rules;
2655 : bool keep_policies;
2656 : bool keep_partkey;
2657 :
2658 : /* Build temporary entry, but don't link it into hashtable */
2659 282979 : newrel = RelationBuildDesc(save_relid, false);
2660 :
2661 : /*
2662 : * Between here and the end of the swap, don't add code that does or
2663 : * reasonably could read system catalogs. That range must be free
2664 : * from invalidation processing. See RelationBuildDesc() manipulation
2665 : * of in_progress_list.
2666 : */
2667 :
2668 282975 : if (newrel == NULL)
2669 : {
2670 : /*
2671 : * We can validly get here, if we're using a historic snapshot in
2672 : * which a relation, accessed from outside logical decoding, is
2673 : * still invisible. In that case it's fine to just mark the
2674 : * relation as invalid and return - it'll fully get reloaded by
2675 : * the cache reset at the end of logical decoding (or at the next
2676 : * access). During normal processing we don't want to ignore this
2677 : * case as it shouldn't happen there, as explained below.
2678 : */
2679 0 : if (HistoricSnapshotActive())
2680 0 : return;
2681 :
2682 : /*
2683 : * This shouldn't happen as dropping a relation is intended to be
2684 : * impossible if still referenced (cf. CheckTableNotInUse()). But
2685 : * if we get here anyway, we can't just delete the relcache entry,
2686 : * as it possibly could get accessed later (as e.g. the error
2687 : * might get trapped and handled via a subtransaction rollback).
2688 : */
2689 0 : elog(ERROR, "relation %u deleted while still in use", save_relid);
2690 : }
2691 :
2692 : /*
2693 : * If we were to, again, have cases of the relkind of a relcache entry
2694 : * changing, we would need to ensure that pgstats does not get
2695 : * confused.
2696 : */
2697 : Assert(relation->rd_rel->relkind == newrel->rd_rel->relkind);
2698 :
2699 282975 : keep_tupdesc = equalTupleDescs(relation->rd_att, newrel->rd_att);
2700 282975 : keep_rules = equalRuleLocks(relation->rd_rules, newrel->rd_rules);
2701 282975 : keep_policies = equalRSDesc(relation->rd_rsdesc, newrel->rd_rsdesc);
2702 : /* partkey is immutable once set up, so we can always keep it */
2703 282975 : keep_partkey = (relation->rd_partkey != NULL);
2704 :
2705 : /*
2706 : * Perform swapping of the relcache entry contents. Within this
2707 : * process the old entry is momentarily invalid, so there *must* be no
2708 : * possibility of CHECK_FOR_INTERRUPTS within this sequence. Do it in
2709 : * all-in-line code for safety.
2710 : *
2711 : * Since the vast majority of fields should be swapped, our method is
2712 : * to swap the whole structures and then re-swap those few fields we
2713 : * didn't want swapped.
2714 : */
2715 : #define SWAPFIELD(fldtype, fldname) \
2716 : do { \
2717 : fldtype _tmp = newrel->fldname; \
2718 : newrel->fldname = relation->fldname; \
2719 : relation->fldname = _tmp; \
2720 : } while (0)
2721 :
2722 : /* swap all Relation struct fields */
2723 : {
2724 : RelationData tmpstruct;
2725 :
2726 282975 : memcpy(&tmpstruct, newrel, sizeof(RelationData));
2727 282975 : memcpy(newrel, relation, sizeof(RelationData));
2728 282975 : memcpy(relation, &tmpstruct, sizeof(RelationData));
2729 : }
2730 :
2731 : /* rd_smgr must not be swapped, due to back-links from smgr level */
2732 282975 : SWAPFIELD(SMgrRelation, rd_smgr);
2733 : /* rd_refcnt must be preserved */
2734 282975 : SWAPFIELD(int, rd_refcnt);
2735 : /* isnailed shouldn't change */
2736 : Assert(newrel->rd_isnailed == relation->rd_isnailed);
2737 : /* creation sub-XIDs must be preserved */
2738 282975 : SWAPFIELD(SubTransactionId, rd_createSubid);
2739 282975 : SWAPFIELD(SubTransactionId, rd_newRelfilelocatorSubid);
2740 282975 : SWAPFIELD(SubTransactionId, rd_firstRelfilelocatorSubid);
2741 282975 : SWAPFIELD(SubTransactionId, rd_droppedSubid);
2742 : /* un-swap rd_rel pointers, swap contents instead */
2743 282975 : SWAPFIELD(Form_pg_class, rd_rel);
2744 : /* ... but actually, we don't have to update newrel->rd_rel */
2745 282975 : memcpy(relation->rd_rel, newrel->rd_rel, CLASS_TUPLE_SIZE);
2746 : /* preserve old tupledesc, rules, policies if no logical change */
2747 282975 : if (keep_tupdesc)
2748 266873 : SWAPFIELD(TupleDesc, rd_att);
2749 282975 : if (keep_rules)
2750 : {
2751 271725 : SWAPFIELD(RuleLock *, rd_rules);
2752 271725 : SWAPFIELD(MemoryContext, rd_rulescxt);
2753 : }
2754 282975 : if (keep_policies)
2755 282725 : SWAPFIELD(RowSecurityDesc *, rd_rsdesc);
2756 : /* toast OID override must be preserved */
2757 282975 : SWAPFIELD(Oid, rd_toastoid);
2758 : /* pgstat_info / enabled must be preserved */
2759 282975 : SWAPFIELD(struct PgStat_TableStatus *, pgstat_info);
2760 282975 : SWAPFIELD(bool, pgstat_enabled);
2761 : /* preserve old partition key if we have one */
2762 282975 : if (keep_partkey)
2763 : {
2764 11286 : SWAPFIELD(PartitionKey, rd_partkey);
2765 11286 : SWAPFIELD(MemoryContext, rd_partkeycxt);
2766 : }
2767 282975 : if (newrel->rd_pdcxt != NULL || newrel->rd_pddcxt != NULL)
2768 : {
2769 : /*
2770 : * We are rebuilding a partitioned relation with a non-zero
2771 : * reference count, so we must keep the old partition descriptor
2772 : * around, in case there's a PartitionDirectory with a pointer to
2773 : * it. This means we can't free the old rd_pdcxt yet. (This is
2774 : * necessary because RelationGetPartitionDesc hands out direct
2775 : * pointers to the relcache's data structure, unlike our usual
2776 : * practice which is to hand out copies. We'd have the same
2777 : * problem with rd_partkey, except that we always preserve that
2778 : * once created.)
2779 : *
2780 : * To ensure that it's not leaked completely, re-attach it to the
2781 : * new reldesc, or make it a child of the new reldesc's rd_pdcxt
2782 : * in the unlikely event that there is one already. (Compare hack
2783 : * in RelationBuildPartitionDesc.) RelationClose will clean up
2784 : * any such contexts once the reference count reaches zero.
2785 : *
2786 : * In the case where the reference count is zero, this code is not
2787 : * reached, which should be OK because in that case there should
2788 : * be no PartitionDirectory with a pointer to the old entry.
2789 : *
2790 : * Note that newrel and relation have already been swapped, so the
2791 : * "old" partition descriptor is actually the one hanging off of
2792 : * newrel.
2793 : */
2794 8877 : relation->rd_partdesc = NULL; /* ensure rd_partdesc is invalid */
2795 8877 : relation->rd_partdesc_nodetached = NULL;
2796 8877 : relation->rd_partdesc_nodetached_xmin = InvalidTransactionId;
2797 8877 : if (relation->rd_pdcxt != NULL) /* probably never happens */
2798 0 : MemoryContextSetParent(newrel->rd_pdcxt, relation->rd_pdcxt);
2799 : else
2800 8877 : relation->rd_pdcxt = newrel->rd_pdcxt;
2801 8877 : if (relation->rd_pddcxt != NULL)
2802 0 : MemoryContextSetParent(newrel->rd_pddcxt, relation->rd_pddcxt);
2803 : else
2804 8877 : relation->rd_pddcxt = newrel->rd_pddcxt;
2805 : /* drop newrel's pointers so we don't destroy it below */
2806 8877 : newrel->rd_partdesc = NULL;
2807 8877 : newrel->rd_partdesc_nodetached = NULL;
2808 8877 : newrel->rd_partdesc_nodetached_xmin = InvalidTransactionId;
2809 8877 : newrel->rd_pdcxt = NULL;
2810 8877 : newrel->rd_pddcxt = NULL;
2811 : }
2812 :
2813 : #undef SWAPFIELD
2814 :
2815 : /* And now we can throw away the temporary entry */
2816 282975 : RelationDestroyRelation(newrel, !keep_tupdesc);
2817 : }
2818 : }
2819 :
2820 : /*
2821 : * RelationFlushRelation
2822 : *
2823 : * Rebuild the relation if it is open (refcount > 0), else blow it away.
2824 : * This is used when we receive a cache invalidation event for the rel.
2825 : */
2826 : static void
2827 575131 : RelationFlushRelation(Relation relation)
2828 : {
2829 575131 : if (relation->rd_createSubid != InvalidSubTransactionId ||
2830 346882 : relation->rd_firstRelfilelocatorSubid != InvalidSubTransactionId)
2831 : {
2832 : /*
2833 : * New relcache entries are always rebuilt, not flushed; else we'd
2834 : * forget the "new" status of the relation. Ditto for the
2835 : * new-relfilenumber status.
2836 : */
2837 479330 : if (IsTransactionState() && relation->rd_droppedSubid == InvalidSubTransactionId)
2838 : {
2839 : /*
2840 : * The rel could have zero refcnt here, so temporarily increment
2841 : * the refcnt to ensure it's safe to rebuild it. We can assume
2842 : * that the current transaction has some lock on the rel already.
2843 : */
2844 238429 : RelationIncrementReferenceCount(relation);
2845 238429 : RelationRebuildRelation(relation);
2846 238425 : RelationDecrementReferenceCount(relation);
2847 : }
2848 : else
2849 1238 : RelationInvalidateRelation(relation);
2850 : }
2851 : else
2852 : {
2853 : /*
2854 : * Pre-existing rels can be dropped from the relcache if not open.
2855 : *
2856 : * If the entry is in use, rebuild it if possible. If we're not
2857 : * inside a valid transaction, we can't do any catalog access so it's
2858 : * not possible to rebuild yet. Just mark it as invalid in that case,
2859 : * so that the rebuild will occur when the entry is next opened.
2860 : *
2861 : * Note: it's possible that we come here during subtransaction abort,
2862 : * and the reason for wanting to rebuild is that the rel is open in
2863 : * the outer transaction. In that case it might seem unsafe to not
2864 : * rebuild immediately, since whatever code has the rel already open
2865 : * will keep on using the relcache entry as-is. However, in such a
2866 : * case the outer transaction should be holding a lock that's
2867 : * sufficient to prevent any significant change in the rel's schema,
2868 : * so the existing entry contents should be good enough for its
2869 : * purposes; at worst we might be behind on statistics updates or the
2870 : * like. (See also CheckTableNotInUse() and its callers.)
2871 : */
2872 335464 : if (RelationHasReferenceCountZero(relation))
2873 213075 : RelationClearRelation(relation);
2874 122389 : else if (!IsTransactionState())
2875 11541 : RelationInvalidateRelation(relation);
2876 110848 : else if (relation->rd_isnailed && relation->rd_refcnt == 1)
2877 : {
2878 : /*
2879 : * A nailed relation with refcnt == 1 is unused. We cannot clear
2880 : * it, but there's also no need no need to rebuild it immediately.
2881 : */
2882 2036 : RelationInvalidateRelation(relation);
2883 : }
2884 : else
2885 108812 : RelationRebuildRelation(relation);
2886 : }
2887 575127 : }
2888 :
2889 : /*
2890 : * RelationForgetRelation - caller reports that it dropped the relation
2891 : */
2892 : void
2893 49865 : RelationForgetRelation(Oid rid)
2894 : {
2895 : Relation relation;
2896 :
2897 49865 : RelationIdCacheLookup(rid, relation);
2898 :
2899 49865 : if (!relation)
2900 0 : return; /* not in cache, nothing to do */
2901 :
2902 49865 : if (!RelationHasReferenceCountZero(relation))
2903 0 : elog(ERROR, "relation %u is still open", rid);
2904 :
2905 : Assert(relation->rd_droppedSubid == InvalidSubTransactionId);
2906 49865 : if (relation->rd_createSubid != InvalidSubTransactionId ||
2907 48879 : relation->rd_firstRelfilelocatorSubid != InvalidSubTransactionId)
2908 : {
2909 : /*
2910 : * In the event of subtransaction rollback, we must not forget
2911 : * rd_*Subid. Mark the entry "dropped" and invalidate it, instead of
2912 : * destroying it right away. (If we're in a top transaction, we could
2913 : * opt to destroy the entry.)
2914 : */
2915 1019 : relation->rd_droppedSubid = GetCurrentSubTransactionId();
2916 1019 : RelationInvalidateRelation(relation);
2917 : }
2918 : else
2919 48846 : RelationClearRelation(relation);
2920 : }
2921 :
2922 : /*
2923 : * RelationCacheInvalidateEntry
2924 : *
2925 : * This routine is invoked for SI cache flush messages.
2926 : *
2927 : * Any relcache entry matching the relid must be flushed. (Note: caller has
2928 : * already determined that the relid belongs to our database or is a shared
2929 : * relation.)
2930 : *
2931 : * We used to skip local relations, on the grounds that they could
2932 : * not be targets of cross-backend SI update messages; but it seems
2933 : * safer to process them, so that our *own* SI update messages will
2934 : * have the same effects during CommandCounterIncrement for both
2935 : * local and nonlocal relations.
2936 : */
2937 : void
2938 2202723 : RelationCacheInvalidateEntry(Oid relationId)
2939 : {
2940 : Relation relation;
2941 :
2942 2202723 : RelationIdCacheLookup(relationId, relation);
2943 :
2944 2202723 : if (relation)
2945 : {
2946 575131 : relcacheInvalsReceived++;
2947 575131 : RelationFlushRelation(relation);
2948 : }
2949 : else
2950 : {
2951 : int i;
2952 :
2953 1655689 : for (i = 0; i < in_progress_list_len; i++)
2954 28097 : if (in_progress_list[i].reloid == relationId)
2955 4 : in_progress_list[i].invalidated = true;
2956 : }
2957 2202719 : }
2958 :
2959 : /*
2960 : * RelationCacheInvalidate
2961 : * Blow away cached relation descriptors that have zero reference counts,
2962 : * and rebuild those with positive reference counts. Also reset the smgr
2963 : * relation cache and re-read relation mapping data.
2964 : *
2965 : * Apart from debug_discard_caches, this is currently used only to recover
2966 : * from SI message buffer overflow, so we do not touch relations having
2967 : * new-in-transaction relfilenumbers; they cannot be targets of cross-backend
2968 : * SI updates (and our own updates now go through a separate linked list
2969 : * that isn't limited by the SI message buffer size).
2970 : *
2971 : * We do this in two phases: the first pass deletes deletable items, and
2972 : * the second one rebuilds the rebuildable items. This is essential for
2973 : * safety, because hash_seq_search only copes with concurrent deletion of
2974 : * the element it is currently visiting. If a second SI overflow were to
2975 : * occur while we are walking the table, resulting in recursive entry to
2976 : * this routine, we could crash because the inner invocation blows away
2977 : * the entry next to be visited by the outer scan. But this way is OK,
2978 : * because (a) during the first pass we won't process any more SI messages,
2979 : * so hash_seq_search will complete safely; (b) during the second pass we
2980 : * only hold onto pointers to nondeletable entries.
2981 : *
2982 : * The two-phase approach also makes it easy to update relfilenumbers for
2983 : * mapped relations before we do anything else, and to ensure that the
2984 : * second pass processes nailed-in-cache items before other nondeletable
2985 : * items. This should ensure that system catalogs are up to date before
2986 : * we attempt to use them to reload information about other open relations.
2987 : *
2988 : * After those two phases of work having immediate effects, we normally
2989 : * signal any RelationBuildDesc() on the stack to start over. However, we
2990 : * don't do this if called as part of debug_discard_caches. Otherwise,
2991 : * RelationBuildDesc() would become an infinite loop.
2992 : */
2993 : void
2994 3515 : RelationCacheInvalidate(bool debug_discard)
2995 : {
2996 : HASH_SEQ_STATUS status;
2997 : RelIdCacheEnt *idhentry;
2998 : Relation relation;
2999 3515 : List *rebuildFirstList = NIL;
3000 3515 : List *rebuildList = NIL;
3001 : ListCell *l;
3002 : int i;
3003 :
3004 : /*
3005 : * Reload relation mapping data before starting to reconstruct cache.
3006 : */
3007 3515 : RelationMapInvalidateAll();
3008 :
3009 : /* Phase 1 */
3010 3515 : hash_seq_init(&status, RelationIdCache);
3011 :
3012 392184 : while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3013 : {
3014 388669 : relation = idhentry->reldesc;
3015 :
3016 : /*
3017 : * Ignore new relations; no other backend will manipulate them before
3018 : * we commit. Likewise, before replacing a relation's relfilelocator,
3019 : * we shall have acquired AccessExclusiveLock and drained any
3020 : * applicable pending invalidations.
3021 : */
3022 388669 : if (relation->rd_createSubid != InvalidSubTransactionId ||
3023 388597 : relation->rd_firstRelfilelocatorSubid != InvalidSubTransactionId)
3024 83 : continue;
3025 :
3026 388586 : relcacheInvalsReceived++;
3027 :
3028 388586 : if (RelationHasReferenceCountZero(relation))
3029 : {
3030 : /* Delete this entry immediately */
3031 315622 : RelationClearRelation(relation);
3032 : }
3033 : else
3034 : {
3035 : /*
3036 : * If it's a mapped relation, immediately update its rd_locator in
3037 : * case its relfilenumber changed. We must do this during phase 1
3038 : * in case the relation is consulted during rebuild of other
3039 : * relcache entries in phase 2. It's safe since consulting the
3040 : * map doesn't involve any access to relcache entries.
3041 : */
3042 72964 : if (RelationIsMapped(relation))
3043 : {
3044 56503 : RelationCloseSmgr(relation);
3045 56503 : RelationInitPhysicalAddr(relation);
3046 : }
3047 :
3048 : /*
3049 : * Add this entry to list of stuff to rebuild in second pass.
3050 : * pg_class goes to the front of rebuildFirstList while
3051 : * pg_class_oid_index goes to the back of rebuildFirstList, so
3052 : * they are done first and second respectively. Other nailed
3053 : * relations go to the front of rebuildList, so they'll be done
3054 : * next in no particular order; and everything else goes to the
3055 : * back of rebuildList.
3056 : */
3057 72964 : if (RelationGetRelid(relation) == RelationRelationId)
3058 3244 : rebuildFirstList = lcons(relation, rebuildFirstList);
3059 69720 : else if (RelationGetRelid(relation) == ClassOidIndexId)
3060 3244 : rebuildFirstList = lappend(rebuildFirstList, relation);
3061 66476 : else if (relation->rd_isnailed)
3062 66235 : rebuildList = lcons(relation, rebuildList);
3063 : else
3064 241 : rebuildList = lappend(rebuildList, relation);
3065 : }
3066 : }
3067 :
3068 : /*
3069 : * We cannot destroy the SMgrRelations as there might still be references
3070 : * to them, but close the underlying file descriptors.
3071 : */
3072 3515 : smgrreleaseall();
3073 :
3074 : /*
3075 : * Phase 2: rebuild (or invalidate) the items found to need rebuild in
3076 : * phase 1
3077 : */
3078 10003 : foreach(l, rebuildFirstList)
3079 : {
3080 6488 : relation = (Relation) lfirst(l);
3081 6488 : if (!IsTransactionState() || (relation->rd_isnailed && relation->rd_refcnt == 1))
3082 6486 : RelationInvalidateRelation(relation);
3083 : else
3084 2 : RelationRebuildRelation(relation);
3085 : }
3086 3515 : list_free(rebuildFirstList);
3087 69991 : foreach(l, rebuildList)
3088 : {
3089 66476 : relation = (Relation) lfirst(l);
3090 66476 : if (!IsTransactionState() || (relation->rd_isnailed && relation->rd_refcnt == 1))
3091 66226 : RelationInvalidateRelation(relation);
3092 : else
3093 250 : RelationRebuildRelation(relation);
3094 : }
3095 3515 : list_free(rebuildList);
3096 :
3097 3515 : if (!debug_discard)
3098 : /* Any RelationBuildDesc() on the stack must start over. */
3099 3527 : for (i = 0; i < in_progress_list_len; i++)
3100 12 : in_progress_list[i].invalidated = true;
3101 3515 : }
3102 :
3103 : static void
3104 15911 : RememberToFreeTupleDescAtEOX(TupleDesc td)
3105 : {
3106 15911 : if (EOXactTupleDescArray == NULL)
3107 : {
3108 : MemoryContext oldcxt;
3109 :
3110 8793 : oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
3111 :
3112 8793 : EOXactTupleDescArray = (TupleDesc *) palloc(16 * sizeof(TupleDesc));
3113 8793 : EOXactTupleDescArrayLen = 16;
3114 8793 : NextEOXactTupleDescNum = 0;
3115 8793 : MemoryContextSwitchTo(oldcxt);
3116 : }
3117 7118 : else if (NextEOXactTupleDescNum >= EOXactTupleDescArrayLen)
3118 : {
3119 38 : int32 newlen = EOXactTupleDescArrayLen * 2;
3120 :
3121 : Assert(EOXactTupleDescArrayLen > 0);
3122 :
3123 38 : EOXactTupleDescArray = (TupleDesc *) repalloc(EOXactTupleDescArray,
3124 : newlen * sizeof(TupleDesc));
3125 38 : EOXactTupleDescArrayLen = newlen;
3126 : }
3127 :
3128 15911 : EOXactTupleDescArray[NextEOXactTupleDescNum++] = td;
3129 15911 : }
3130 :
3131 : #ifdef USE_ASSERT_CHECKING
3132 : static void
3133 : AssertPendingSyncConsistency(Relation relation)
3134 : {
3135 : bool relcache_verdict =
3136 : RelationIsPermanent(relation) &&
3137 : ((relation->rd_createSubid != InvalidSubTransactionId &&
3138 : RELKIND_HAS_STORAGE(relation->rd_rel->relkind)) ||
3139 : relation->rd_firstRelfilelocatorSubid != InvalidSubTransactionId);
3140 :
3141 : Assert(relcache_verdict == RelFileLocatorSkippingWAL(relation->rd_locator));
3142 :
3143 : if (relation->rd_droppedSubid != InvalidSubTransactionId)
3144 : Assert(!relation->rd_isvalid &&
3145 : (relation->rd_createSubid != InvalidSubTransactionId ||
3146 : relation->rd_firstRelfilelocatorSubid != InvalidSubTransactionId));
3147 : }
3148 :
3149 : /*
3150 : * AssertPendingSyncs_RelationCache
3151 : *
3152 : * Assert that relcache.c and storage.c agree on whether to skip WAL.
3153 : */
3154 : void
3155 : AssertPendingSyncs_RelationCache(void)
3156 : {
3157 : HASH_SEQ_STATUS status;
3158 : LOCALLOCK *locallock;
3159 : Relation *rels;
3160 : int maxrels;
3161 : int nrels;
3162 : RelIdCacheEnt *idhentry;
3163 : int i;
3164 :
3165 : /*
3166 : * Open every relation that this transaction has locked. If, for some
3167 : * relation, storage.c is skipping WAL and relcache.c is not skipping WAL,
3168 : * a CommandCounterIncrement() typically yields a local invalidation
3169 : * message that destroys the relcache entry. By recreating such entries
3170 : * here, we detect the problem.
3171 : */
3172 : PushActiveSnapshot(GetTransactionSnapshot());
3173 : maxrels = 1;
3174 : rels = palloc(maxrels * sizeof(*rels));
3175 : nrels = 0;
3176 : hash_seq_init(&status, GetLockMethodLocalHash());
3177 : while ((locallock = (LOCALLOCK *) hash_seq_search(&status)) != NULL)
3178 : {
3179 : Oid relid;
3180 : Relation r;
3181 :
3182 : if (locallock->nLocks <= 0)
3183 : continue;
3184 : if ((LockTagType) locallock->tag.lock.locktag_type !=
3185 : LOCKTAG_RELATION)
3186 : continue;
3187 : relid = locallock->tag.lock.locktag_field2;
3188 : r = RelationIdGetRelation(relid);
3189 : if (!RelationIsValid(r))
3190 : continue;
3191 : if (nrels >= maxrels)
3192 : {
3193 : maxrels *= 2;
3194 : rels = repalloc(rels, maxrels * sizeof(*rels));
3195 : }
3196 : rels[nrels++] = r;
3197 : }
3198 :
3199 : hash_seq_init(&status, RelationIdCache);
3200 : while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3201 : AssertPendingSyncConsistency(idhentry->reldesc);
3202 :
3203 : for (i = 0; i < nrels; i++)
3204 : RelationClose(rels[i]);
3205 : PopActiveSnapshot();
3206 : }
3207 : #endif
3208 :
3209 : /*
3210 : * AtEOXact_RelationCache
3211 : *
3212 : * Clean up the relcache at main-transaction commit or abort.
3213 : *
3214 : * Note: this must be called *before* processing invalidation messages.
3215 : * In the case of abort, we don't want to try to rebuild any invalidated
3216 : * cache entries (since we can't safely do database accesses). Therefore
3217 : * we must reset refcnts before handling pending invalidations.
3218 : *
3219 : * As of PostgreSQL 8.1, relcache refcnts should get released by the
3220 : * ResourceOwner mechanism. This routine just does a debugging
3221 : * cross-check that no pins remain. However, we also need to do special
3222 : * cleanup when the current transaction created any relations or made use
3223 : * of forced index lists.
3224 : */
3225 : void
3226 663385 : AtEOXact_RelationCache(bool isCommit)
3227 : {
3228 : HASH_SEQ_STATUS status;
3229 : RelIdCacheEnt *idhentry;
3230 : int i;
3231 :
3232 : /*
3233 : * Forget in_progress_list. This is relevant when we're aborting due to
3234 : * an error during RelationBuildDesc().
3235 : */
3236 : Assert(in_progress_list_len == 0 || !isCommit);
3237 663385 : in_progress_list_len = 0;
3238 :
3239 : /*
3240 : * Unless the eoxact_list[] overflowed, we only need to examine the rels
3241 : * listed in it. Otherwise fall back on a hash_seq_search scan.
3242 : *
3243 : * For simplicity, eoxact_list[] entries are not deleted till end of
3244 : * top-level transaction, even though we could remove them at
3245 : * subtransaction end in some cases, or remove relations from the list if
3246 : * they are cleared for other reasons. Therefore we should expect the
3247 : * case that list entries are not found in the hashtable; if not, there's
3248 : * nothing to do for them.
3249 : */
3250 663385 : if (eoxact_list_overflowed)
3251 : {
3252 94 : hash_seq_init(&status, RelationIdCache);
3253 26991 : while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3254 : {
3255 26897 : AtEOXact_cleanup(idhentry->reldesc, isCommit);
3256 : }
3257 : }
3258 : else
3259 : {
3260 743405 : for (i = 0; i < eoxact_list_len; i++)
3261 : {
3262 80114 : idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3263 80114 : &eoxact_list[i],
3264 : HASH_FIND,
3265 : NULL);
3266 80114 : if (idhentry != NULL)
3267 78500 : AtEOXact_cleanup(idhentry->reldesc, isCommit);
3268 : }
3269 : }
3270 :
3271 663385 : if (EOXactTupleDescArrayLen > 0)
3272 : {
3273 : Assert(EOXactTupleDescArray != NULL);
3274 24704 : for (i = 0; i < NextEOXactTupleDescNum; i++)
3275 15911 : FreeTupleDesc(EOXactTupleDescArray[i]);
3276 8793 : pfree(EOXactTupleDescArray);
3277 8793 : EOXactTupleDescArray = NULL;
3278 : }
3279 :
3280 : /* Now we're out of the transaction and can clear the lists */
3281 663385 : eoxact_list_len = 0;
3282 663385 : eoxact_list_overflowed = false;
3283 663385 : NextEOXactTupleDescNum = 0;
3284 663385 : EOXactTupleDescArrayLen = 0;
3285 663385 : }
3286 :
3287 : /*
3288 : * AtEOXact_cleanup
3289 : *
3290 : * Clean up a single rel at main-transaction commit or abort
3291 : *
3292 : * NB: this processing must be idempotent, because EOXactListAdd() doesn't
3293 : * bother to prevent duplicate entries in eoxact_list[].
3294 : */
3295 : static void
3296 105397 : AtEOXact_cleanup(Relation relation, bool isCommit)
3297 : {
3298 105397 : bool clear_relcache = false;
3299 :
3300 : /*
3301 : * The relcache entry's ref count should be back to its normal
3302 : * not-in-a-transaction state: 0 unless it's nailed in cache.
3303 : *
3304 : * In bootstrap mode, this is NOT true, so don't check it --- the
3305 : * bootstrap code expects relations to stay open across start/commit
3306 : * transaction calls. (That seems bogus, but it's not worth fixing.)
3307 : *
3308 : * Note: ideally this check would be applied to every relcache entry, not
3309 : * just those that have eoxact work to do. But it's not worth forcing a
3310 : * scan of the whole relcache just for this. (Moreover, doing so would
3311 : * mean that assert-enabled testing never tests the hash_search code path
3312 : * above, which seems a bad idea.)
3313 : */
3314 : #ifdef USE_ASSERT_CHECKING
3315 : if (!IsBootstrapProcessingMode())
3316 : {
3317 : int expected_refcnt;
3318 :
3319 : expected_refcnt = relation->rd_isnailed ? 1 : 0;
3320 : Assert(relation->rd_refcnt == expected_refcnt);
3321 : }
3322 : #endif
3323 :
3324 : /*
3325 : * Is the relation live after this transaction ends?
3326 : *
3327 : * During commit, clear the relcache entry if it is preserved after
3328 : * relation drop, in order not to orphan the entry. During rollback,
3329 : * clear the relcache entry if the relation is created in the current
3330 : * transaction since it isn't interesting any longer once we are out of
3331 : * the transaction.
3332 : */
3333 105397 : clear_relcache =
3334 : (isCommit ?
3335 102022 : relation->rd_droppedSubid != InvalidSubTransactionId :
3336 105397 : relation->rd_createSubid != InvalidSubTransactionId);
3337 :
3338 : /*
3339 : * Since we are now out of the transaction, reset the subids to zero. That
3340 : * also lets RelationClearRelation() drop the relcache entry.
3341 : */
3342 105397 : relation->rd_createSubid = InvalidSubTransactionId;
3343 105397 : relation->rd_newRelfilelocatorSubid = InvalidSubTransactionId;
3344 105397 : relation->rd_firstRelfilelocatorSubid = InvalidSubTransactionId;
3345 105397 : relation->rd_droppedSubid = InvalidSubTransactionId;
3346 :
3347 105397 : if (clear_relcache)
3348 : {
3349 3811 : if (RelationHasReferenceCountZero(relation))
3350 : {
3351 3811 : RelationClearRelation(relation);
3352 3811 : return;
3353 : }
3354 : else
3355 : {
3356 : /*
3357 : * Hmm, somewhere there's a (leaked?) reference to the relation.
3358 : * We daren't remove the entry for fear of dereferencing a
3359 : * dangling pointer later. Bleat, and mark it as not belonging to
3360 : * the current transaction. Hopefully it'll get cleaned up
3361 : * eventually. This must be just a WARNING to avoid
3362 : * error-during-error-recovery loops.
3363 : */
3364 0 : elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
3365 : RelationGetRelationName(relation));
3366 : }
3367 : }
3368 : }
3369 :
3370 : /*
3371 : * AtEOSubXact_RelationCache
3372 : *
3373 : * Clean up the relcache at sub-transaction commit or abort.
3374 : *
3375 : * Note: this must be called *before* processing invalidation messages.
3376 : */
3377 : void
3378 11061 : AtEOSubXact_RelationCache(bool isCommit, SubTransactionId mySubid,
3379 : SubTransactionId parentSubid)
3380 : {
3381 : HASH_SEQ_STATUS status;
3382 : RelIdCacheEnt *idhentry;
3383 : int i;
3384 :
3385 : /*
3386 : * Forget in_progress_list. This is relevant when we're aborting due to
3387 : * an error during RelationBuildDesc(). We don't commit subtransactions
3388 : * during RelationBuildDesc().
3389 : */
3390 : Assert(in_progress_list_len == 0 || !isCommit);
3391 11061 : in_progress_list_len = 0;
3392 :
3393 : /*
3394 : * Unless the eoxact_list[] overflowed, we only need to examine the rels
3395 : * listed in it. Otherwise fall back on a hash_seq_search scan. Same
3396 : * logic as in AtEOXact_RelationCache.
3397 : */
3398 11061 : if (eoxact_list_overflowed)
3399 : {
3400 0 : hash_seq_init(&status, RelationIdCache);
3401 0 : while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
3402 : {
3403 0 : AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3404 : mySubid, parentSubid);
3405 : }
3406 : }
3407 : else
3408 : {
3409 17478 : for (i = 0; i < eoxact_list_len; i++)
3410 : {
3411 6417 : idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
3412 6417 : &eoxact_list[i],
3413 : HASH_FIND,
3414 : NULL);
3415 6417 : if (idhentry != NULL)
3416 5760 : AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
3417 : mySubid, parentSubid);
3418 : }
3419 : }
3420 :
3421 : /* Don't reset the list; we still need more cleanup later */
3422 11061 : }
3423 :
3424 : /*
3425 : * AtEOSubXact_cleanup
3426 : *
3427 : * Clean up a single rel at subtransaction commit or abort
3428 : *
3429 : * NB: this processing must be idempotent, because EOXactListAdd() doesn't
3430 : * bother to prevent duplicate entries in eoxact_list[].
3431 : */
3432 : static void
3433 5760 : AtEOSubXact_cleanup(Relation relation, bool isCommit,
3434 : SubTransactionId mySubid, SubTransactionId parentSubid)
3435 : {
3436 : /*
3437 : * Is it a relation created in the current subtransaction?
3438 : *
3439 : * During subcommit, mark it as belonging to the parent, instead, as long
3440 : * as it has not been dropped. Otherwise simply delete the relcache entry.
3441 : * --- it isn't interesting any longer.
3442 : */
3443 5760 : if (relation->rd_createSubid == mySubid)
3444 : {
3445 : /*
3446 : * Valid rd_droppedSubid means the corresponding relation is dropped
3447 : * but the relcache entry is preserved for at-commit pending sync. We
3448 : * need to drop it explicitly here not to make the entry orphan.
3449 : */
3450 : Assert(relation->rd_droppedSubid == mySubid ||
3451 : relation->rd_droppedSubid == InvalidSubTransactionId);
3452 126 : if (isCommit && relation->rd_droppedSubid == InvalidSubTransactionId)
3453 45 : relation->rd_createSubid = parentSubid;
3454 81 : else if (RelationHasReferenceCountZero(relation))
3455 : {
3456 : /* allow the entry to be removed */
3457 81 : relation->rd_createSubid = InvalidSubTransactionId;
3458 81 : relation->rd_newRelfilelocatorSubid = InvalidSubTransactionId;
3459 81 : relation->rd_firstRelfilelocatorSubid = InvalidSubTransactionId;
3460 81 : relation->rd_droppedSubid = InvalidSubTransactionId;
3461 81 : RelationClearRelation(relation);
3462 81 : return;
3463 : }
3464 : else
3465 : {
3466 : /*
3467 : * Hmm, somewhere there's a (leaked?) reference to the relation.
3468 : * We daren't remove the entry for fear of dereferencing a
3469 : * dangling pointer later. Bleat, and transfer it to the parent
3470 : * subtransaction so we can try again later. This must be just a
3471 : * WARNING to avoid error-during-error-recovery loops.
3472 : */
3473 0 : relation->rd_createSubid = parentSubid;
3474 0 : elog(WARNING, "cannot remove relcache entry for \"%s\" because it has nonzero refcount",
3475 : RelationGetRelationName(relation));
3476 : }
3477 : }
3478 :
3479 : /*
3480 : * Likewise, update or drop any new-relfilenumber-in-subtransaction record
3481 : * or drop record.
3482 : */
3483 5679 : if (relation->rd_newRelfilelocatorSubid == mySubid)
3484 : {
3485 102 : if (isCommit)
3486 55 : relation->rd_newRelfilelocatorSubid = parentSubid;
3487 : else
3488 47 : relation->rd_newRelfilelocatorSubid = InvalidSubTransactionId;
3489 : }
3490 :
3491 5679 : if (relation->rd_firstRelfilelocatorSubid == mySubid)
3492 : {
3493 74 : if (isCommit)
3494 37 : relation->rd_firstRelfilelocatorSubid = parentSubid;
3495 : else
3496 37 : relation->rd_firstRelfilelocatorSubid = InvalidSubTransactionId;
3497 : }
3498 :
3499 5679 : if (relation->rd_droppedSubid == mySubid)
3500 : {
3501 21 : if (isCommit)
3502 1 : relation->rd_droppedSubid = parentSubid;
3503 : else
3504 20 : relation->rd_droppedSubid = InvalidSubTransactionId;
3505 : }
3506 : }
3507 :
3508 :
3509 : /*
3510 : * RelationBuildLocalRelation
3511 : * Build a relcache entry for an about-to-be-created relation,
3512 : * and enter it into the relcache.
3513 : */
3514 : Relation
3515 90137 : RelationBuildLocalRelation(const char *relname,
3516 : Oid relnamespace,
3517 : TupleDesc tupDesc,
3518 : Oid relid,
3519 : Oid accessmtd,
3520 : RelFileNumber relfilenumber,
3521 : Oid reltablespace,
3522 : bool shared_relation,
3523 : bool mapped_relation,
3524 : char relpersistence,
3525 : char relkind)
3526 : {
3527 : Relation rel;
3528 : MemoryContext oldcxt;
3529 90137 : int natts = tupDesc->natts;
3530 : int i;
3531 : bool has_not_null;
3532 : bool nailit;
3533 :
3534 : Assert(natts >= 0);
3535 :
3536 : /*
3537 : * check for creation of a rel that must be nailed in cache.
3538 : *
3539 : * XXX this list had better match the relations specially handled in
3540 : * RelationCacheInitializePhase2/3.
3541 : */
3542 90137 : switch (relid)
3543 : {
3544 399 : case DatabaseRelationId:
3545 : case AuthIdRelationId:
3546 : case AuthMemRelationId:
3547 : case RelationRelationId:
3548 : case AttributeRelationId:
3549 : case ProcedureRelationId:
3550 : case TypeRelationId:
3551 399 : nailit = true;
3552 399 : break;
3553 89738 : default:
3554 89738 : nailit = false;
3555 89738 : break;
3556 : }
3557 :
3558 : /*
3559 : * check that hardwired list of shared rels matches what's in the
3560 : * bootstrap .bki file. If you get a failure here during initdb, you
3561 : * probably need to fix IsSharedRelation() to match whatever you've done
3562 : * to the set of shared relations.
3563 : */
3564 90137 : if (shared_relation != IsSharedRelation(relid))
3565 0 : elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)",
3566 : relname, relid);
3567 :
3568 : /* Shared relations had better be mapped, too */
3569 : Assert(mapped_relation || !shared_relation);
3570 :
3571 : /*
3572 : * switch to the cache context to create the relcache entry.
3573 : */
3574 90137 : if (!CacheMemoryContext)
3575 0 : CreateCacheMemoryContext();
3576 :
3577 90137 : oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
3578 :
3579 : /*
3580 : * allocate a new relation descriptor and fill in basic state fields.
3581 : */
3582 90137 : rel = palloc0_object(RelationData);
3583 :
3584 : /* make sure relation is marked as having no open file yet */
3585 90137 : rel->rd_smgr = NULL;
3586 :
3587 : /* mark it nailed if appropriate */
3588 90137 : rel->rd_isnailed = nailit;
3589 :
3590 90137 : rel->rd_refcnt = nailit ? 1 : 0;
3591 :
3592 : /* it's being created in this transaction */
3593 90137 : rel->rd_createSubid = GetCurrentSubTransactionId();
3594 90137 : rel->rd_newRelfilelocatorSubid = InvalidSubTransactionId;
3595 90137 : rel->rd_firstRelfilelocatorSubid = InvalidSubTransactionId;
3596 90137 : rel->rd_droppedSubid = InvalidSubTransactionId;
3597 :
3598 : /*
3599 : * create a new tuple descriptor from the one passed in. We do this
3600 : * partly to copy it into the cache context, and partly because the new
3601 : * relation can't have any defaults or constraints yet; they have to be
3602 : * added in later steps, because they require additions to multiple system
3603 : * catalogs. We can copy attnotnull constraints here, however.
3604 : */
3605 90137 : rel->rd_att = CreateTupleDescCopy(tupDesc);
3606 90137 : rel->rd_att->tdrefcount = 1; /* mark as refcounted */
3607 90137 : has_not_null = false;
3608 384581 : for (i = 0; i < natts; i++)
3609 : {
3610 294444 : Form_pg_attribute satt = TupleDescAttr(tupDesc, i);
3611 294444 : Form_pg_attribute datt = TupleDescAttr(rel->rd_att, i);
3612 :
3613 294444 : datt->attidentity = satt->attidentity;
3614 294444 : datt->attgenerated = satt->attgenerated;
3615 294444 : datt->attnotnull = satt->attnotnull;
3616 294444 : has_not_null |= satt->attnotnull;
3617 294444 : populate_compact_attribute(rel->rd_att, i);
3618 :
3619 294444 : if (satt->attnotnull)
3620 : {
3621 47664 : CompactAttribute *scatt = TupleDescCompactAttr(tupDesc, i);
3622 47664 : CompactAttribute *dcatt = TupleDescCompactAttr(rel->rd_att, i);
3623 :
3624 47664 : dcatt->attnullability = scatt->attnullability;
3625 : }
3626 : }
3627 :
3628 90137 : if (has_not_null)
3629 : {
3630 13677 : TupleConstr *constr = palloc0_object(TupleConstr);
3631 :
3632 13677 : constr->has_not_null = true;
3633 13677 : rel->rd_att->constr = constr;
3634 : }
3635 :
3636 : /*
3637 : * initialize relation tuple form (caller may add/override data later)
3638 : */
3639 90137 : rel->rd_rel = (Form_pg_class) palloc0(CLASS_TUPLE_SIZE);
3640 :
3641 90137 : namestrcpy(&rel->rd_rel->relname, relname);
3642 90137 : rel->rd_rel->relnamespace = relnamespace;
3643 :
3644 90137 : rel->rd_rel->relkind = relkind;
3645 90137 : rel->rd_rel->relnatts = natts;
3646 90137 : rel->rd_rel->reltype = InvalidOid;
3647 : /* needed when bootstrapping: */
3648 90137 : rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;
3649 :
3650 : /* set up persistence and relcache fields dependent on it */
3651 90137 : rel->rd_rel->relpersistence = relpersistence;
3652 90137 : switch (relpersistence)
3653 : {
3654 85719 : case RELPERSISTENCE_UNLOGGED:
3655 : case RELPERSISTENCE_PERMANENT:
3656 85719 : rel->rd_backend = INVALID_PROC_NUMBER;
3657 85719 : rel->rd_islocaltemp = false;
3658 85719 : break;
3659 4418 : case RELPERSISTENCE_TEMP:
3660 : Assert(isTempOrTempToastNamespace(relnamespace));
3661 4418 : rel->rd_backend = ProcNumberForTempRelations();
3662 4418 : rel->rd_islocaltemp = true;
3663 4418 : break;
3664 0 : default:
3665 0 : elog(ERROR, "invalid relpersistence: %c", relpersistence);
3666 : break;
3667 : }
3668 :
3669 : /* if it's a materialized view, it's not populated initially */
3670 90137 : if (relkind == RELKIND_MATVIEW)
3671 278 : rel->rd_rel->relispopulated = false;
3672 : else
3673 89859 : rel->rd_rel->relispopulated = true;
3674 :
3675 : /* set replica identity -- system catalogs and non-tables don't have one */
3676 90137 : if (!IsCatalogNamespace(relnamespace) &&
3677 48783 : (relkind == RELKIND_RELATION ||
3678 48505 : relkind == RELKIND_MATVIEW ||
3679 : relkind == RELKIND_PARTITIONED_TABLE))
3680 28693 : rel->rd_rel->relreplident = REPLICA_IDENTITY_DEFAULT;
3681 : else
3682 61444 : rel->rd_rel->relreplident = REPLICA_IDENTITY_NOTHING;
3683 :
3684 : /*
3685 : * Insert relation physical and logical identifiers (OIDs) into the right
3686 : * places. For a mapped relation, we set relfilenumber to zero and rely
3687 : * on RelationInitPhysicalAddr to consult the map.
3688 : */
3689 90137 : rel->rd_rel->relisshared = shared_relation;
3690 :
3691 90137 : RelationGetRelid(rel) = relid;
3692 :
3693 384581 : for (i = 0; i < natts; i++)
3694 294444 : TupleDescAttr(rel->rd_att, i)->attrelid = relid;
3695 :
3696 90137 : TupleDescFinalize(rel->rd_att);
3697 :
3698 90137 : rel->rd_rel->reltablespace = reltablespace;
3699 :
3700 90137 : if (mapped_relation)
3701 : {
3702 3680 : rel->rd_rel->relfilenode = InvalidRelFileNumber;
3703 : /* Add it to the active mapping information */
3704 3680 : RelationMapUpdateMap(relid, relfilenumber, shared_relation, true);
3705 : }
3706 : else
3707 86457 : rel->rd_rel->relfilenode = relfilenumber;
3708 :
3709 90137 : RelationInitLockInfo(rel); /* see lmgr.c */
3710 :
3711 90137 : RelationInitPhysicalAddr(rel);
3712 :
3713 90137 : rel->rd_rel->relam = accessmtd;
3714 :
3715 : /*
3716 : * RelationInitTableAccessMethod will do syscache lookups, so we mustn't
3717 : * run it in CacheMemoryContext. Fortunately, the remaining steps don't
3718 : * require a long-lived current context.
3719 : */
3720 90137 : MemoryContextSwitchTo(oldcxt);
3721 :
3722 90137 : if (RELKIND_HAS_TABLE_AM(relkind) || relkind == RELKIND_SEQUENCE)
3723 41704 : RelationInitTableAccessMethod(rel);
3724 :
3725 : /*
3726 : * Leave index access method uninitialized, because the pg_index row has
3727 : * not been inserted at this stage of index creation yet. The cache
3728 : * invalidation after pg_index row has been inserted will initialize it.
3729 : */
3730 :
3731 : /*
3732 : * Okay to insert into the relcache hash table.
3733 : *
3734 : * Ordinarily, there should certainly not be an existing hash entry for
3735 : * the same OID; but during bootstrap, when we create a "real" relcache
3736 : * entry for one of the bootstrap relations, we'll be overwriting the
3737 : * phony one created with formrdesc. So allow that to happen for nailed
3738 : * rels.
3739 : */
3740 90137 : RelationCacheInsert(rel, nailit);
3741 :
3742 : /*
3743 : * Flag relation as needing eoxact cleanup (to clear rd_createSubid). We
3744 : * can't do this before storing relid in it.
3745 : */
3746 90137 : EOXactListAdd(rel);
3747 :
3748 : /* It's fully valid */
3749 90137 : rel->rd_isvalid = true;
3750 :
3751 : /*
3752 : * Caller expects us to pin the returned entry.
3753 : */
3754 90137 : RelationIncrementReferenceCount(rel);
3755 :
3756 90137 : return rel;
3757 : }
3758 :
3759 :
3760 : /*
3761 : * RelationSetNewRelfilenumber
3762 : *
3763 : * Assign a new relfilenumber (physical file name), and possibly a new
3764 : * persistence setting, to the relation.
3765 : *
3766 : * This allows a full rewrite of the relation to be done with transactional
3767 : * safety (since the filenumber assignment can be rolled back). Note however
3768 : * that there is no simple way to access the relation's old data for the
3769 : * remainder of the current transaction. This limits the usefulness to cases
3770 : * such as TRUNCATE or rebuilding an index from scratch.
3771 : *
3772 : * Caller must already hold exclusive lock on the relation.
3773 : */
3774 : void
3775 8427 : RelationSetNewRelfilenumber(Relation relation, char persistence)
3776 : {
3777 : RelFileNumber newrelfilenumber;
3778 : Relation pg_class;
3779 : ItemPointerData otid;
3780 : HeapTuple tuple;
3781 : Form_pg_class classform;
3782 8427 : MultiXactId minmulti = InvalidMultiXactId;
3783 8427 : TransactionId freezeXid = InvalidTransactionId;
3784 : RelFileLocator newrlocator;
3785 :
3786 8427 : if (!IsBinaryUpgrade)
3787 : {
3788 : /* Allocate a new relfilenumber */
3789 8299 : newrelfilenumber = GetNewRelFileNumber(relation->rd_rel->reltablespace,
3790 : NULL, persistence);
3791 : }
3792 128 : else if (relation->rd_rel->relkind == RELKIND_INDEX)
3793 : {
3794 64 : if (!OidIsValid(binary_upgrade_next_index_pg_class_relfilenumber))
3795 0 : ereport(ERROR,
3796 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3797 : errmsg("index relfilenumber value not set when in binary upgrade mode")));
3798 :
3799 64 : newrelfilenumber = binary_upgrade_next_index_pg_class_relfilenumber;
3800 64 : binary_upgrade_next_index_pg_class_relfilenumber = InvalidOid;
3801 : }
3802 64 : else if (relation->rd_rel->relkind == RELKIND_RELATION)
3803 : {
3804 64 : if (!OidIsValid(binary_upgrade_next_heap_pg_class_relfilenumber))
3805 0 : ereport(ERROR,
3806 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3807 : errmsg("heap relfilenumber value not set when in binary upgrade mode")));
3808 :
3809 64 : newrelfilenumber = binary_upgrade_next_heap_pg_class_relfilenumber;
3810 64 : binary_upgrade_next_heap_pg_class_relfilenumber = InvalidOid;
3811 : }
3812 : else
3813 0 : ereport(ERROR,
3814 : (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3815 : errmsg("unexpected request for new relfilenumber in binary upgrade mode")));
3816 :
3817 : /*
3818 : * Get a writable copy of the pg_class tuple for the given relation.
3819 : */
3820 8427 : pg_class = table_open(RelationRelationId, RowExclusiveLock);
3821 :
3822 8427 : tuple = SearchSysCacheLockedCopy1(RELOID,
3823 : ObjectIdGetDatum(RelationGetRelid(relation)));
3824 8427 : if (!HeapTupleIsValid(tuple))
3825 0 : elog(ERROR, "could not find tuple for relation %u",
3826 : RelationGetRelid(relation));
3827 8427 : otid = tuple->t_self;
3828 8427 : classform = (Form_pg_class) GETSTRUCT(tuple);
3829 :
3830 : /*
3831 : * Schedule unlinking of the old storage at transaction commit, except
3832 : * when performing a binary upgrade, when we must do it immediately.
3833 : */
3834 8427 : if (IsBinaryUpgrade)
3835 : {
3836 : SMgrRelation srel;
3837 :
3838 : /*
3839 : * During a binary upgrade, we use this code path to ensure that
3840 : * pg_largeobject and its index have the same relfilenumbers as in the
3841 : * old cluster. This is necessary because pg_upgrade treats
3842 : * pg_largeobject like a user table, not a system table. It is however
3843 : * possible that a table or index may need to end up with the same
3844 : * relfilenumber in the new cluster as what it had in the old cluster.
3845 : * Hence, we can't wait until commit time to remove the old storage.
3846 : *
3847 : * In general, this function needs to have transactional semantics,
3848 : * and removing the old storage before commit time surely isn't.
3849 : * However, it doesn't really matter, because if a binary upgrade
3850 : * fails at this stage, the new cluster will need to be recreated
3851 : * anyway.
3852 : */
3853 128 : srel = smgropen(relation->rd_locator, relation->rd_backend);
3854 128 : smgrdounlinkall(&srel, 1, false);
3855 128 : smgrclose(srel);
3856 : }
3857 : else
3858 : {
3859 : /* Not a binary upgrade, so just schedule it to happen later. */
3860 8299 : RelationDropStorage(relation);
3861 : }
3862 :
3863 : /*
3864 : * Create storage for the main fork of the new relfilenumber. If it's a
3865 : * table-like object, call into the table AM to do so, which'll also
3866 : * create the table's init fork if needed.
3867 : *
3868 : * NOTE: If relevant for the AM, any conflict in relfilenumber value will
3869 : * be caught here, if GetNewRelFileNumber messes up for any reason.
3870 : */
3871 8427 : newrlocator = relation->rd_locator;
3872 8427 : newrlocator.relNumber = newrelfilenumber;
3873 :
3874 8427 : if (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind))
3875 : {
3876 3171 : table_relation_set_new_filelocator(relation, &newrlocator,
3877 : persistence,
3878 : &freezeXid, &minmulti);
3879 : }
3880 5256 : else if (RELKIND_HAS_STORAGE(relation->rd_rel->relkind))
3881 5256 : {
3882 : /* handle these directly, at least for now */
3883 : SMgrRelation srel;
3884 :
3885 5256 : srel = RelationCreateStorage(newrlocator, persistence, true);
3886 5256 : smgrclose(srel);
3887 : }
3888 : else
3889 : {
3890 : /* we shouldn't be called for anything else */
3891 0 : elog(ERROR, "relation \"%s\" does not have storage",
3892 : RelationGetRelationName(relation));
3893 : }
3894 :
3895 : /*
3896 : * If we're dealing with a mapped index, pg_class.relfilenode doesn't
3897 : * change; instead we have to send the update to the relation mapper.
3898 : *
3899 : * For mapped indexes, we don't actually change the pg_class entry at all;
3900 : * this is essential when reindexing pg_class itself. That leaves us with
3901 : * possibly-inaccurate values of relpages etc, but those will be fixed up
3902 : * later.
3903 : */
3904 8427 : if (RelationIsMapped(relation))
3905 : {
3906 : /* This case is only supported for indexes */
3907 : Assert(relation->rd_rel->relkind == RELKIND_INDEX);
3908 :
3909 : /* Since we're not updating pg_class, these had better not change */
3910 : Assert(classform->relfrozenxid == freezeXid);
3911 : Assert(classform->relminmxid == minmulti);
3912 : Assert(classform->relpersistence == persistence);
3913 :
3914 : /*
3915 : * In some code paths it's possible that the tuple update we'd
3916 : * otherwise do here is the only thing that would assign an XID for
3917 : * the current transaction. However, we must have an XID to delete
3918 : * files, so make sure one is assigned.
3919 : */
3920 498 : (void) GetCurrentTransactionId();
3921 :
3922 : /* Do the deed */
3923 498 : RelationMapUpdateMap(RelationGetRelid(relation),
3924 : newrelfilenumber,
3925 498 : relation->rd_rel->relisshared,
3926 : false);
3927 :
3928 : /* Since we're not updating pg_class, must trigger inval manually */
3929 498 : CacheInvalidateRelcache(relation);
3930 : }
3931 : else
3932 : {
3933 : /* Normal case, update the pg_class entry */
3934 7929 : classform->relfilenode = newrelfilenumber;
3935 :
3936 : /* relpages etc. never change for sequences */
3937 7929 : if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
3938 : {
3939 7735 : classform->relpages = 0; /* it's empty until further notice */
3940 7735 : classform->reltuples = -1;
3941 7735 : classform->relallvisible = 0;
3942 7735 : classform->relallfrozen = 0;
3943 : }
3944 7929 : classform->relfrozenxid = freezeXid;
3945 7929 : classform->relminmxid = minmulti;
3946 7929 : classform->relpersistence = persistence;
3947 :
3948 7929 : CatalogTupleUpdate(pg_class, &otid, tuple);
3949 : }
3950 :
3951 8427 : UnlockTuple(pg_class, &otid, InplaceUpdateTupleLock);
3952 8427 : heap_freetuple(tuple);
3953 :
3954 8427 : table_close(pg_class, RowExclusiveLock);
3955 :
3956 : /*
3957 : * Make the pg_class row change or relation map change visible. This will
3958 : * cause the relcache entry to get updated, too.
3959 : */
3960 8427 : CommandCounterIncrement();
3961 :
3962 8427 : RelationAssumeNewRelfilelocator(relation);
3963 8427 : }
3964 :
3965 : /*
3966 : * RelationAssumeNewRelfilelocator
3967 : *
3968 : * Code that modifies pg_class.reltablespace or pg_class.relfilenode must call
3969 : * this. The call shall precede any code that might insert WAL records whose
3970 : * replay would modify bytes in the new RelFileLocator, and the call shall follow
3971 : * any WAL modifying bytes in the prior RelFileLocator. See struct RelationData.
3972 : * Ideally, call this as near as possible to the CommandCounterIncrement()
3973 : * that makes the pg_class change visible (before it or after it); that
3974 : * minimizes the chance of future development adding a forbidden WAL insertion
3975 : * between RelationAssumeNewRelfilelocator() and CommandCounterIncrement().
3976 : */
3977 : void
3978 10273 : RelationAssumeNewRelfilelocator(Relation relation)
3979 : {
3980 10273 : relation->rd_newRelfilelocatorSubid = GetCurrentSubTransactionId();
3981 10273 : if (relation->rd_firstRelfilelocatorSubid == InvalidSubTransactionId)
3982 10196 : relation->rd_firstRelfilelocatorSubid = relation->rd_newRelfilelocatorSubid;
3983 :
3984 : /* Flag relation as needing eoxact cleanup (to clear these fields) */
3985 10273 : EOXactListAdd(relation);
3986 10273 : }
3987 :
3988 :
3989 : /*
3990 : * RelationCacheInitialize
3991 : *
3992 : * This initializes the relation descriptor cache. At the time
3993 : * that this is invoked, we can't do database access yet (mainly
3994 : * because the transaction subsystem is not up); all we are doing
3995 : * is making an empty cache hashtable. This must be done before
3996 : * starting the initialization transaction, because otherwise
3997 : * AtEOXact_RelationCache would crash if that transaction aborts
3998 : * before we can get the relcache set up.
3999 : */
4000 :
4001 : #define INITRELCACHESIZE 400
4002 :
4003 : void
4004 20333 : RelationCacheInitialize(void)
4005 : {
4006 : HASHCTL ctl;
4007 : int allocsize;
4008 :
4009 : /*
4010 : * make sure cache memory context exists
4011 : */
4012 20333 : if (!CacheMemoryContext)
4013 20333 : CreateCacheMemoryContext();
4014 :
4015 : /*
4016 : * create hashtable that indexes the relcache
4017 : */
4018 20333 : ctl.keysize = sizeof(Oid);
4019 20333 : ctl.entrysize = sizeof(RelIdCacheEnt);
4020 20333 : RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
4021 : &ctl, HASH_ELEM | HASH_BLOBS);
4022 :
4023 : /*
4024 : * reserve enough in_progress_list slots for many cases
4025 : */
4026 20333 : allocsize = 4;
4027 20333 : in_progress_list =
4028 20333 : MemoryContextAlloc(CacheMemoryContext,
4029 : allocsize * sizeof(*in_progress_list));
4030 20333 : in_progress_list_maxlen = allocsize;
4031 :
4032 : /*
4033 : * relation mapper needs to be initialized too
4034 : */
4035 20333 : RelationMapInitialize();
4036 20333 : }
4037 :
4038 : /*
4039 : * RelationCacheInitializePhase2
4040 : *
4041 : * This is called to prepare for access to shared catalogs during startup.
4042 : * We must at least set up nailed reldescs for pg_database, pg_authid,
4043 : * pg_auth_members, and pg_shseclabel. Ideally we'd like to have reldescs
4044 : * for their indexes, too. We attempt to load this information from the
4045 : * shared relcache init file. If that's missing or broken, just make
4046 : * phony entries for the catalogs themselves.
4047 : * RelationCacheInitializePhase3 will clean up as needed.
4048 : */
4049 : void
4050 20333 : RelationCacheInitializePhase2(void)
4051 : {
4052 : MemoryContext oldcxt;
4053 :
4054 : /*
4055 : * relation mapper needs initialized too
4056 : */
4057 20333 : RelationMapInitializePhase2();
4058 :
4059 : /*
4060 : * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
4061 : * nothing.
4062 : */
4063 20333 : if (IsBootstrapProcessingMode())
4064 57 : return;
4065 :
4066 : /*
4067 : * switch to cache memory context
4068 : */
4069 20276 : oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
4070 :
4071 : /*
4072 : * Try to load the shared relcache cache file. If unsuccessful, bootstrap
4073 : * the cache with pre-made descriptors for the critical shared catalogs.
4074 : */
4075 20276 : if (!load_relcache_init_file(true))
4076 : {
4077 2603 : formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
4078 : Natts_pg_database, Desc_pg_database);
4079 2603 : formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
4080 : Natts_pg_authid, Desc_pg_authid);
4081 2603 : formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
4082 : Natts_pg_auth_members, Desc_pg_auth_members);
4083 2603 : formrdesc("pg_shseclabel", SharedSecLabelRelation_Rowtype_Id, true,
4084 : Natts_pg_shseclabel, Desc_pg_shseclabel);
4085 2603 : formrdesc("pg_subscription", SubscriptionRelation_Rowtype_Id, true,
4086 : Natts_pg_subscription, Desc_pg_subscription);
4087 :
4088 : #define NUM_CRITICAL_SHARED_RELS 5 /* fix if you change list above */
4089 : }
4090 :
4091 20276 : MemoryContextSwitchTo(oldcxt);
4092 : }
4093 :
4094 : /*
4095 : * RelationCacheInitializePhase3
4096 : *
4097 : * This is called as soon as the catcache and transaction system
4098 : * are functional and we have determined MyDatabaseId. At this point
4099 : * we can actually read data from the database's system catalogs.
4100 : * We first try to read pre-computed relcache entries from the local
4101 : * relcache init file. If that's missing or broken, make phony entries
4102 : * for the minimum set of nailed-in-cache relations. Then (unless
4103 : * bootstrapping) make sure we have entries for the critical system
4104 : * indexes. Once we've done all this, we have enough infrastructure to
4105 : * open any system catalog or use any catcache. The last step is to
4106 : * rewrite the cache files if needed.
4107 : */
4108 : void
4109 18707 : RelationCacheInitializePhase3(void)
4110 : {
4111 : HASH_SEQ_STATUS status;
4112 : RelIdCacheEnt *idhentry;
4113 : MemoryContext oldcxt;
4114 18707 : bool needNewCacheFile = !criticalSharedRelcachesBuilt;
4115 :
4116 : /*
4117 : * relation mapper needs initialized too
4118 : */
4119 18707 : RelationMapInitializePhase3();
4120 :
4121 : /*
4122 : * switch to cache memory context
4123 : */
4124 18707 : oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
4125 :
4126 : /*
4127 : * Try to load the local relcache cache file. If unsuccessful, bootstrap
4128 : * the cache with pre-made descriptors for the critical "nailed-in" system
4129 : * catalogs.
4130 : */
4131 18707 : if (IsBootstrapProcessingMode() ||
4132 18650 : !load_relcache_init_file(false))
4133 : {
4134 1894 : needNewCacheFile = true;
4135 :
4136 1894 : formrdesc("pg_class", RelationRelation_Rowtype_Id, false,
4137 : Natts_pg_class, Desc_pg_class);
4138 1894 : formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false,
4139 : Natts_pg_attribute, Desc_pg_attribute);
4140 1894 : formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false,
4141 : Natts_pg_proc, Desc_pg_proc);
4142 1894 : formrdesc("pg_type", TypeRelation_Rowtype_Id, false,
4143 : Natts_pg_type, Desc_pg_type);
4144 :
4145 : #define NUM_CRITICAL_LOCAL_RELS 4 /* fix if you change list above */
4146 : }
4147 :
4148 18707 : MemoryContextSwitchTo(oldcxt);
4149 :
4150 : /* In bootstrap mode, the faked-up formrdesc info is all we'll have */
4151 18707 : if (IsBootstrapProcessingMode())
4152 57 : return;
4153 :
4154 : /*
4155 : * If we didn't get the critical system indexes loaded into relcache, do
4156 : * so now. These are critical because the catcache and/or opclass cache
4157 : * depend on them for fetches done during relcache load. Thus, we have an
4158 : * infinite-recursion problem. We can break the recursion by doing
4159 : * heapscans instead of indexscans at certain key spots. To avoid hobbling
4160 : * performance, we only want to do that until we have the critical indexes
4161 : * loaded into relcache. Thus, the flag criticalRelcachesBuilt is used to
4162 : * decide whether to do heapscan or indexscan at the key spots, and we set
4163 : * it true after we've loaded the critical indexes.
4164 : *
4165 : * The critical indexes are marked as "nailed in cache", partly to make it
4166 : * easy for load_relcache_init_file to count them, but mainly because we
4167 : * cannot flush and rebuild them once we've set criticalRelcachesBuilt to
4168 : * true. (NOTE: perhaps it would be possible to reload them by
4169 : * temporarily setting criticalRelcachesBuilt to false again. For now,
4170 : * though, we just nail 'em in.)
4171 : *
4172 : * RewriteRelRulenameIndexId and TriggerRelidNameIndexId are not critical
4173 : * in the same way as the others, because the critical catalogs don't
4174 : * (currently) have any rules or triggers, and so these indexes can be
4175 : * rebuilt without inducing recursion. However they are used during
4176 : * relcache load when a rel does have rules or triggers, so we choose to
4177 : * nail them for performance reasons.
4178 : */
4179 18650 : if (!criticalRelcachesBuilt)
4180 : {
4181 1837 : load_critical_index(ClassOidIndexId,
4182 : RelationRelationId);
4183 1837 : load_critical_index(AttributeRelidNumIndexId,
4184 : AttributeRelationId);
4185 1837 : load_critical_index(IndexRelidIndexId,
4186 : IndexRelationId);
4187 1837 : load_critical_index(OpclassOidIndexId,
4188 : OperatorClassRelationId);
4189 1837 : load_critical_index(AccessMethodProcedureIndexId,
4190 : AccessMethodProcedureRelationId);
4191 1837 : load_critical_index(RewriteRelRulenameIndexId,
4192 : RewriteRelationId);
4193 1837 : load_critical_index(TriggerRelidNameIndexId,
4194 : TriggerRelationId);
4195 :
4196 : #define NUM_CRITICAL_LOCAL_INDEXES 7 /* fix if you change list above */
4197 :
4198 1837 : criticalRelcachesBuilt = true;
4199 : }
4200 :
4201 : /*
4202 : * Process critical shared indexes too.
4203 : *
4204 : * DatabaseNameIndexId isn't critical for relcache loading, but rather for
4205 : * initial lookup of MyDatabaseId, without which we'll never find any
4206 : * non-shared catalogs at all. Autovacuum calls InitPostgres with a
4207 : * database OID, so it instead depends on DatabaseOidIndexId. We also
4208 : * need to nail up some indexes on pg_authid and pg_auth_members for use
4209 : * during client authentication. SharedSecLabelObjectIndexId isn't
4210 : * critical for the core system, but authentication hooks might be
4211 : * interested in it.
4212 : */
4213 18650 : if (!criticalSharedRelcachesBuilt)
4214 : {
4215 1447 : load_critical_index(DatabaseNameIndexId,
4216 : DatabaseRelationId);
4217 1447 : load_critical_index(DatabaseOidIndexId,
4218 : DatabaseRelationId);
4219 1447 : load_critical_index(AuthIdRolnameIndexId,
4220 : AuthIdRelationId);
4221 1447 : load_critical_index(AuthIdOidIndexId,
4222 : AuthIdRelationId);
4223 1447 : load_critical_index(AuthMemMemRoleIndexId,
4224 : AuthMemRelationId);
4225 1447 : load_critical_index(SharedSecLabelObjectIndexId,
4226 : SharedSecLabelRelationId);
4227 :
4228 : #define NUM_CRITICAL_SHARED_INDEXES 6 /* fix if you change list above */
4229 :
4230 1447 : criticalSharedRelcachesBuilt = true;
4231 : }
4232 :
4233 : /*
4234 : * Now, scan all the relcache entries and update anything that might be
4235 : * wrong in the results from formrdesc or the relcache cache file. If we
4236 : * faked up relcache entries using formrdesc, then read the real pg_class
4237 : * rows and replace the fake entries with them. Also, if any of the
4238 : * relcache entries have rules, triggers, or security policies, load that
4239 : * info the hard way since it isn't recorded in the cache file.
4240 : *
4241 : * Whenever we access the catalogs to read data, there is a possibility of
4242 : * a shared-inval cache flush causing relcache entries to be removed.
4243 : * Since hash_seq_search only guarantees to still work after the *current*
4244 : * entry is removed, it's unsafe to continue the hashtable scan afterward.
4245 : * We handle this by restarting the scan from scratch after each access.
4246 : * This is theoretically O(N^2), but the number of entries that actually
4247 : * need to be fixed is small enough that it doesn't matter.
4248 : */
4249 18650 : hash_seq_init(&status, RelationIdCache);
4250 :
4251 2917712 : while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
4252 : {
4253 2880412 : Relation relation = idhentry->reldesc;
4254 2880412 : bool restart = false;
4255 :
4256 : /*
4257 : * Make sure *this* entry doesn't get flushed while we work with it.
4258 : */
4259 2880412 : RelationIncrementReferenceCount(relation);
4260 :
4261 : /*
4262 : * If it's a faked-up entry, read the real pg_class tuple.
4263 : */
4264 2880412 : if (relation->rd_rel->relowner == InvalidOid)
4265 : {
4266 : HeapTuple htup;
4267 : Form_pg_class relp;
4268 :
4269 14583 : htup = SearchSysCache1(RELOID,
4270 : ObjectIdGetDatum(RelationGetRelid(relation)));
4271 14583 : if (!HeapTupleIsValid(htup))
4272 0 : ereport(FATAL,
4273 : errcode(ERRCODE_UNDEFINED_OBJECT),
4274 : errmsg_internal("cache lookup failed for relation %u",
4275 : RelationGetRelid(relation)));
4276 14583 : relp = (Form_pg_class) GETSTRUCT(htup);
4277 :
4278 : /*
4279 : * Copy tuple to relation->rd_rel. (See notes in
4280 : * AllocateRelationDesc())
4281 : */
4282 14583 : memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);
4283 :
4284 : /* Update rd_options while we have the tuple */
4285 14583 : if (relation->rd_options)
4286 0 : pfree(relation->rd_options);
4287 14583 : RelationParseRelOptions(relation, htup);
4288 :
4289 : /*
4290 : * Check the values in rd_att were set up correctly. (We cannot
4291 : * just copy them over now: formrdesc must have set up the rd_att
4292 : * data correctly to start with, because it may already have been
4293 : * copied into one or more catcache entries.)
4294 : */
4295 : Assert(relation->rd_att->tdtypeid == relp->reltype);
4296 : Assert(relation->rd_att->tdtypmod == -1);
4297 :
4298 14583 : ReleaseSysCache(htup);
4299 :
4300 : /* relowner had better be OK now, else we'll loop forever */
4301 14583 : if (relation->rd_rel->relowner == InvalidOid)
4302 0 : elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
4303 : RelationGetRelationName(relation));
4304 :
4305 14583 : restart = true;
4306 : }
4307 :
4308 : /*
4309 : * Fix data that isn't saved in relcache cache file.
4310 : *
4311 : * relhasrules or relhastriggers could possibly be wrong or out of
4312 : * date. If we don't actually find any rules or triggers, clear the
4313 : * local copy of the flag so that we don't get into an infinite loop
4314 : * here. We don't make any attempt to fix the pg_class entry, though.
4315 : */
4316 2880412 : if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
4317 : {
4318 0 : RelationBuildRuleLock(relation);
4319 0 : if (relation->rd_rules == NULL)
4320 0 : relation->rd_rel->relhasrules = false;
4321 0 : restart = true;
4322 : }
4323 2880412 : if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
4324 : {
4325 0 : RelationBuildTriggers(relation);
4326 0 : if (relation->trigdesc == NULL)
4327 0 : relation->rd_rel->relhastriggers = false;
4328 0 : restart = true;
4329 : }
4330 :
4331 : /*
4332 : * Re-load the row security policies if the relation has them, since
4333 : * they are not preserved in the cache. Note that we can never NOT
4334 : * have a policy while relrowsecurity is true,
4335 : * RelationBuildRowSecurity will create a single default-deny policy
4336 : * if there is no policy defined in pg_policy.
4337 : */
4338 2880412 : if (relation->rd_rel->relrowsecurity && relation->rd_rsdesc == NULL)
4339 : {
4340 0 : RelationBuildRowSecurity(relation);
4341 :
4342 : Assert(relation->rd_rsdesc != NULL);
4343 0 : restart = true;
4344 : }
4345 :
4346 : /* Reload tableam data if needed */
4347 2880412 : if (relation->rd_tableam == NULL &&
4348 1764582 : (RELKIND_HAS_TABLE_AM(relation->rd_rel->relkind) || relation->rd_rel->relkind == RELKIND_SEQUENCE))
4349 : {
4350 0 : RelationInitTableAccessMethod(relation);
4351 : Assert(relation->rd_tableam != NULL);
4352 :
4353 0 : restart = true;
4354 : }
4355 :
4356 : /* Release hold on the relation */
4357 2880412 : RelationDecrementReferenceCount(relation);
4358 :
4359 : /* Now, restart the hashtable scan if needed */
4360 2880412 : if (restart)
4361 : {
4362 14583 : hash_seq_term(&status);
4363 14583 : hash_seq_init(&status, RelationIdCache);
4364 : }
4365 : }
4366 :
4367 : /*
4368 : * Lastly, write out new relcache cache files if needed. We don't bother
4369 : * to distinguish cases where only one of the two needs an update.
4370 : */
4371 18650 : if (needNewCacheFile)
4372 : {
4373 : /*
4374 : * Force all the catcaches to finish initializing and thereby open the
4375 : * catalogs and indexes they use. This will preload the relcache with
4376 : * entries for all the most important system catalogs and indexes, so
4377 : * that the init files will be most useful for future backends.
4378 : */
4379 2051 : InitCatalogCachePhase2();
4380 :
4381 : /* now write the files */
4382 2051 : write_relcache_init_file(true);
4383 2051 : write_relcache_init_file(false);
4384 : }
4385 : }
4386 :
4387 : /*
4388 : * Load one critical system index into the relcache
4389 : *
4390 : * indexoid is the OID of the target index, heapoid is the OID of the catalog
4391 : * it belongs to.
4392 : */
4393 : static void
4394 21541 : load_critical_index(Oid indexoid, Oid heapoid)
4395 : {
4396 : Relation ird;
4397 :
4398 : /*
4399 : * We must lock the underlying catalog before locking the index to avoid
4400 : * deadlock, since RelationBuildDesc might well need to read the catalog,
4401 : * and if anyone else is exclusive-locking this catalog and index they'll
4402 : * be doing it in that order.
4403 : */
4404 21541 : LockRelationOid(heapoid, AccessShareLock);
4405 21541 : LockRelationOid(indexoid, AccessShareLock);
4406 21541 : ird = RelationBuildDesc(indexoid, true);
4407 21541 : if (ird == NULL)
4408 0 : ereport(PANIC,
4409 : errcode(ERRCODE_DATA_CORRUPTED),
4410 : errmsg_internal("could not open critical system index %u", indexoid));
4411 21541 : ird->rd_isnailed = true;
4412 21541 : ird->rd_refcnt = 1;
4413 21541 : UnlockRelationOid(indexoid, AccessShareLock);
4414 21541 : UnlockRelationOid(heapoid, AccessShareLock);
4415 :
4416 21541 : (void) RelationGetIndexAttOptions(ird, false);
4417 21541 : }
4418 :
4419 : /*
4420 : * GetPgClassDescriptor -- get a predefined tuple descriptor for pg_class
4421 : * GetPgIndexDescriptor -- get a predefined tuple descriptor for pg_index
4422 : *
4423 : * We need this kluge because we have to be able to access non-fixed-width
4424 : * fields of pg_class and pg_index before we have the standard catalog caches
4425 : * available. We use predefined data that's set up in just the same way as
4426 : * the bootstrapped reldescs used by formrdesc(). The resulting tupdesc is
4427 : * not 100% kosher: it does not have the correct rowtype OID in tdtypeid, nor
4428 : * does it have a TupleConstr field. But it's good enough for the purpose of
4429 : * extracting fields.
4430 : */
4431 : static TupleDesc
4432 37414 : BuildHardcodedDescriptor(int natts, const FormData_pg_attribute *attrs)
4433 : {
4434 : TupleDesc result;
4435 : MemoryContext oldcxt;
4436 : int i;
4437 :
4438 37414 : oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
4439 :
4440 37414 : result = CreateTemplateTupleDesc(natts);
4441 37414 : result->tdtypeid = RECORDOID; /* not right, but we don't care */
4442 37414 : result->tdtypmod = -1;
4443 :
4444 1066299 : for (i = 0; i < natts; i++)
4445 : {
4446 1028885 : memcpy(TupleDescAttr(result, i), &attrs[i], ATTRIBUTE_FIXED_PART_SIZE);
4447 :
4448 1028885 : populate_compact_attribute(result, i);
4449 : }
4450 :
4451 37414 : TupleDescFinalize(result);
4452 :
4453 : /* Note: we don't bother to set up a TupleConstr entry */
4454 :
4455 37414 : MemoryContextSwitchTo(oldcxt);
4456 :
4457 37414 : return result;
4458 : }
4459 :
4460 : static TupleDesc
4461 1152896 : GetPgClassDescriptor(void)
4462 : {
4463 : static TupleDesc pgclassdesc = NULL;
4464 :
4465 : /* Already done? */
4466 1152896 : if (pgclassdesc == NULL)
4467 18707 : pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class,
4468 : Desc_pg_class);
4469 :
4470 1152896 : return pgclassdesc;
4471 : }
4472 :
4473 : static TupleDesc
4474 1365658 : GetPgIndexDescriptor(void)
4475 : {
4476 : static TupleDesc pgindexdesc = NULL;
4477 :
4478 : /* Already done? */
4479 1365658 : if (pgindexdesc == NULL)
4480 18707 : pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index,
4481 : Desc_pg_index);
4482 :
4483 1365658 : return pgindexdesc;
4484 : }
4485 :
4486 : /*
4487 : * Load any default attribute value definitions for the relation.
4488 : *
4489 : * ndef is the number of attributes that were marked atthasdef.
4490 : *
4491 : * Note: we don't make it a hard error to be missing some pg_attrdef records.
4492 : * We can limp along as long as nothing needs to use the default value. Code
4493 : * that fails to find an expected AttrDefault record should throw an error.
4494 : */
4495 : static void
4496 25785 : AttrDefaultFetch(Relation relation, int ndef)
4497 : {
4498 : AttrDefault *attrdef;
4499 : Relation adrel;
4500 : SysScanDesc adscan;
4501 : ScanKeyData skey;
4502 : HeapTuple htup;
4503 25785 : int found = 0;
4504 :
4505 : /* Allocate array with room for as many entries as expected */
4506 : attrdef = (AttrDefault *)
4507 25785 : MemoryContextAllocZero(CacheMemoryContext,
4508 : ndef * sizeof(AttrDefault));
4509 :
4510 : /* Search pg_attrdef for relevant entries */
4511 25785 : ScanKeyInit(&skey,
4512 : Anum_pg_attrdef_adrelid,
4513 : BTEqualStrategyNumber, F_OIDEQ,
4514 : ObjectIdGetDatum(RelationGetRelid(relation)));
4515 :
4516 25785 : adrel = table_open(AttrDefaultRelationId, AccessShareLock);
4517 25785 : adscan = systable_beginscan(adrel, AttrDefaultIndexId, true,
4518 : NULL, 1, &skey);
4519 :
4520 63018 : while (HeapTupleIsValid(htup = systable_getnext(adscan)))
4521 : {
4522 37233 : Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup);
4523 : Datum val;
4524 : bool isnull;
4525 :
4526 : /* protect limited size of array */
4527 37233 : if (found >= ndef)
4528 : {
4529 0 : elog(WARNING, "unexpected pg_attrdef record found for attribute %d of relation \"%s\"",
4530 : adform->adnum, RelationGetRelationName(relation));
4531 0 : break;
4532 : }
4533 :
4534 37233 : val = fastgetattr(htup,
4535 : Anum_pg_attrdef_adbin,
4536 : adrel->rd_att, &isnull);
4537 37233 : if (isnull)
4538 0 : elog(WARNING, "null adbin for attribute %d of relation \"%s\"",
4539 : adform->adnum, RelationGetRelationName(relation));
4540 : else
4541 : {
4542 : /* detoast and convert to cstring in caller's context */
4543 37233 : char *s = TextDatumGetCString(val);
4544 :
4545 37233 : attrdef[found].adnum = adform->adnum;
4546 37233 : attrdef[found].adbin = MemoryContextStrdup(CacheMemoryContext, s);
4547 37233 : pfree(s);
4548 37233 : found++;
4549 : }
4550 : }
4551 :
4552 25785 : systable_endscan(adscan);
4553 25785 : table_close(adrel, AccessShareLock);
4554 :
4555 25785 : if (found != ndef)
4556 0 : elog(WARNING, "%d pg_attrdef record(s) missing for relation \"%s\"",
4557 : ndef - found, RelationGetRelationName(relation));
4558 :
4559 : /*
4560 : * Sort the AttrDefault entries by adnum, for the convenience of
4561 : * equalTupleDescs(). (Usually, they already will be in order, but this
4562 : * might not be so if systable_getnext isn't using an index.)
4563 : */
4564 25785 : if (found > 1)
4565 6741 : qsort(attrdef, found, sizeof(AttrDefault), AttrDefaultCmp);
4566 :
4567 : /* Install array only after it's fully valid */
4568 25785 : relation->rd_att->constr->defval = attrdef;
4569 25785 : relation->rd_att->constr->num_defval = found;
4570 25785 : }
4571 :
4572 : /*
4573 : * qsort comparator to sort AttrDefault entries by adnum
4574 : */
4575 : static int
4576 11448 : AttrDefaultCmp(const void *a, const void *b)
4577 : {
4578 11448 : const AttrDefault *ada = (const AttrDefault *) a;
4579 11448 : const AttrDefault *adb = (const AttrDefault *) b;
4580 :
4581 11448 : return pg_cmp_s16(ada->adnum, adb->adnum);
4582 : }
4583 :
4584 : /*
4585 : * Load any check constraints for the relation, and update not-null validity
4586 : * of invalid constraints.
4587 : *
4588 : * As with defaults, if we don't find the expected number of them, just warn
4589 : * here. The executor should throw an error if an INSERT/UPDATE is attempted.
4590 : */
4591 : static void
4592 116078 : CheckNNConstraintFetch(Relation relation)
4593 : {
4594 : ConstrCheck *check;
4595 116078 : int ncheck = relation->rd_rel->relchecks;
4596 : Relation conrel;
4597 : SysScanDesc conscan;
4598 : ScanKeyData skey[1];
4599 : HeapTuple htup;
4600 116078 : int found = 0;
4601 :
4602 : /* Allocate array with room for as many entries as expected, if needed */
4603 116078 : if (ncheck > 0)
4604 : check = (ConstrCheck *)
4605 9246 : MemoryContextAllocZero(CacheMemoryContext,
4606 : ncheck * sizeof(ConstrCheck));
4607 : else
4608 106832 : check = NULL;
4609 :
4610 : /* Search pg_constraint for relevant entries */
4611 116078 : ScanKeyInit(&skey[0],
4612 : Anum_pg_constraint_conrelid,
4613 : BTEqualStrategyNumber, F_OIDEQ,
4614 : ObjectIdGetDatum(RelationGetRelid(relation)));
4615 :
4616 116078 : conrel = table_open(ConstraintRelationId, AccessShareLock);
4617 116078 : conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4618 : NULL, 1, skey);
4619 :
4620 339401 : while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4621 : {
4622 223323 : Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(htup);
4623 : Datum val;
4624 : bool isnull;
4625 :
4626 : /*
4627 : * If this is a not-null constraint, then only look at it if it's
4628 : * invalid, and if so, mark the TupleDesc entry as known invalid.
4629 : * Otherwise move on. We'll mark any remaining columns that are still
4630 : * in UNKNOWN state as known valid later. This allows us not to have
4631 : * to extract the attnum from this constraint tuple in the vast
4632 : * majority of cases.
4633 : */
4634 223323 : if (conform->contype == CONSTRAINT_NOTNULL)
4635 : {
4636 123366 : if (!conform->convalidated)
4637 : {
4638 : AttrNumber attnum;
4639 :
4640 776 : attnum = extractNotNullColumn(htup);
4641 : Assert(relation->rd_att->compact_attrs[attnum - 1].attnullability ==
4642 : ATTNULLABLE_UNKNOWN);
4643 776 : relation->rd_att->compact_attrs[attnum - 1].attnullability =
4644 : ATTNULLABLE_INVALID;
4645 : }
4646 :
4647 207231 : continue;
4648 : }
4649 :
4650 : /* For what follows, consider check constraints only */
4651 99957 : if (conform->contype != CONSTRAINT_CHECK)
4652 83865 : continue;
4653 :
4654 : /* protect limited size of array */
4655 16092 : if (found >= ncheck)
4656 : {
4657 0 : elog(WARNING, "unexpected pg_constraint record found for relation \"%s\"",
4658 : RelationGetRelationName(relation));
4659 0 : break;
4660 : }
4661 :
4662 : /* Grab and test conbin is actually set */
4663 16092 : val = fastgetattr(htup,
4664 : Anum_pg_constraint_conbin,
4665 : conrel->rd_att, &isnull);
4666 16092 : if (isnull)
4667 0 : elog(WARNING, "null conbin for relation \"%s\"",
4668 : RelationGetRelationName(relation));
4669 : else
4670 : {
4671 : /* detoast and convert to cstring in caller's context */
4672 16092 : char *s = TextDatumGetCString(val);
4673 :
4674 16092 : check[found].ccenforced = conform->conenforced;
4675 16092 : check[found].ccvalid = conform->convalidated;
4676 16092 : check[found].ccnoinherit = conform->connoinherit;
4677 32184 : check[found].ccname = MemoryContextStrdup(CacheMemoryContext,
4678 16092 : NameStr(conform->conname));
4679 16092 : check[found].ccbin = MemoryContextStrdup(CacheMemoryContext, s);
4680 :
4681 16092 : pfree(s);
4682 16092 : found++;
4683 : }
4684 : }
4685 :
4686 116078 : systable_endscan(conscan);
4687 116078 : table_close(conrel, AccessShareLock);
4688 :
4689 116078 : if (found != ncheck)
4690 0 : elog(WARNING, "%d pg_constraint record(s) missing for relation \"%s\"",
4691 : ncheck - found, RelationGetRelationName(relation));
4692 :
4693 : /*
4694 : * Sort the records by name. This ensures that CHECKs are applied in a
4695 : * deterministic order, and it also makes equalTupleDescs() faster.
4696 : */
4697 116078 : if (found > 1)
4698 3267 : qsort(check, found, sizeof(ConstrCheck), CheckConstraintCmp);
4699 :
4700 : /* Install array only after it's fully valid */
4701 116078 : relation->rd_att->constr->check = check;
4702 116078 : relation->rd_att->constr->num_check = found;
4703 116078 : }
4704 :
4705 : /*
4706 : * qsort comparator to sort ConstrCheck entries by name
4707 : */
4708 : static int
4709 6846 : CheckConstraintCmp(const void *a, const void *b)
4710 : {
4711 6846 : const ConstrCheck *ca = (const ConstrCheck *) a;
4712 6846 : const ConstrCheck *cb = (const ConstrCheck *) b;
4713 :
4714 6846 : return strcmp(ca->ccname, cb->ccname);
4715 : }
4716 :
4717 : /*
4718 : * RelationGetFKeyList -- get a list of foreign key info for the relation
4719 : *
4720 : * Returns a list of ForeignKeyCacheInfo structs, one per FK constraining
4721 : * the given relation. This data is a direct copy of relevant fields from
4722 : * pg_constraint. The list items are in no particular order.
4723 : *
4724 : * CAUTION: the returned list is part of the relcache's data, and could
4725 : * vanish in a relcache entry reset. Callers must inspect or copy it
4726 : * before doing anything that might trigger a cache flush, such as
4727 : * system catalog accesses. copyObject() can be used if desired.
4728 : * (We define it this way because current callers want to filter and
4729 : * modify the list entries anyway, so copying would be a waste of time.)
4730 : */
4731 : List *
4732 194470 : RelationGetFKeyList(Relation relation)
4733 : {
4734 : List *result;
4735 : Relation conrel;
4736 : SysScanDesc conscan;
4737 : ScanKeyData skey;
4738 : HeapTuple htup;
4739 : List *oldlist;
4740 : MemoryContext oldcxt;
4741 :
4742 : /* Quick exit if we already computed the list. */
4743 194470 : if (relation->rd_fkeyvalid)
4744 161561 : return relation->rd_fkeylist;
4745 :
4746 : /*
4747 : * We build the list we intend to return (in the caller's context) while
4748 : * doing the scan. After successfully completing the scan, we copy that
4749 : * list into the relcache entry. This avoids cache-context memory leakage
4750 : * if we get some sort of error partway through.
4751 : */
4752 32909 : result = NIL;
4753 :
4754 : /* Prepare to scan pg_constraint for entries having conrelid = this rel. */
4755 32909 : ScanKeyInit(&skey,
4756 : Anum_pg_constraint_conrelid,
4757 : BTEqualStrategyNumber, F_OIDEQ,
4758 : ObjectIdGetDatum(RelationGetRelid(relation)));
4759 :
4760 32909 : conrel = table_open(ConstraintRelationId, AccessShareLock);
4761 32909 : conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
4762 : NULL, 1, &skey);
4763 :
4764 100585 : while (HeapTupleIsValid(htup = systable_getnext(conscan)))
4765 : {
4766 67676 : Form_pg_constraint constraint = (Form_pg_constraint) GETSTRUCT(htup);
4767 : ForeignKeyCacheInfo *info;
4768 :
4769 : /* consider only foreign keys */
4770 67676 : if (constraint->contype != CONSTRAINT_FOREIGN)
4771 65057 : continue;
4772 :
4773 2619 : info = makeNode(ForeignKeyCacheInfo);
4774 2619 : info->conoid = constraint->oid;
4775 2619 : info->conrelid = constraint->conrelid;
4776 2619 : info->confrelid = constraint->confrelid;
4777 2619 : info->conenforced = constraint->conenforced;
4778 :
4779 2619 : DeconstructFkConstraintRow(htup, &info->nkeys,
4780 2619 : info->conkey,
4781 2619 : info->confkey,
4782 2619 : info->conpfeqop,
4783 : NULL, NULL, NULL, NULL);
4784 :
4785 : /* Add FK's node to the result list */
4786 2619 : result = lappend(result, info);
4787 : }
4788 :
4789 32909 : systable_endscan(conscan);
4790 32909 : table_close(conrel, AccessShareLock);
4791 :
4792 : /* Now save a copy of the completed list in the relcache entry. */
4793 32909 : oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
4794 32909 : oldlist = relation->rd_fkeylist;
4795 32909 : relation->rd_fkeylist = copyObject(result);
4796 32909 : relation->rd_fkeyvalid = true;
4797 32909 : MemoryContextSwitchTo(oldcxt);
4798 :
4799 : /* Don't leak the old list, if there is one */
4800 32909 : list_free_deep(oldlist);
4801 :
4802 32909 : return result;
4803 : }
4804 :
4805 : /*
4806 : * RelationGetIndexList -- get a list of OIDs of indexes on this relation
4807 : *
4808 : * The index list is created only if someone requests it. We scan pg_index
4809 : * to find relevant indexes, and add the list to the relcache entry so that
4810 : * we won't have to compute it again. Note that shared cache inval of a
4811 : * relcache entry will delete the old list and set rd_indexvalid to false,
4812 : * so that we must recompute the index list on next request. This handles
4813 : * creation or deletion of an index.
4814 : *
4815 : * Indexes that are marked not indislive are omitted from the returned list.
4816 : * Such indexes are expected to be dropped momentarily, and should not be
4817 : * touched at all by any caller of this function.
4818 : *
4819 : * The returned list is guaranteed to be sorted in order by OID. This is
4820 : * needed by the executor, since for index types that we obtain exclusive
4821 : * locks on when updating the index, all backends must lock the indexes in
4822 : * the same order or we will get deadlocks (see ExecOpenIndices()). Any
4823 : * consistent ordering would do, but ordering by OID is easy.
4824 : *
4825 : * Since shared cache inval causes the relcache's copy of the list to go away,
4826 : * we return a copy of the list palloc'd in the caller's context. The caller
4827 : * may list_free() the returned list after scanning it. This is necessary
4828 : * since the caller will typically be doing syscache lookups on the relevant
4829 : * indexes, and syscache lookup could cause SI messages to be processed!
4830 : *
4831 : * In exactly the same way, we update rd_pkindex, which is the OID of the
4832 : * relation's primary key index if any, else InvalidOid; and rd_replidindex,
4833 : * which is the pg_class OID of an index to be used as the relation's
4834 : * replication identity index, or InvalidOid if there is no such index.
4835 : */
4836 : List *
4837 1648634 : RelationGetIndexList(Relation relation)
4838 : {
4839 : Relation indrel;
4840 : SysScanDesc indscan;
4841 : ScanKeyData skey;
4842 : HeapTuple htup;
4843 : List *result;
4844 : List *oldlist;
4845 1648634 : char replident = relation->rd_rel->relreplident;
4846 1648634 : Oid pkeyIndex = InvalidOid;
4847 1648634 : Oid candidateIndex = InvalidOid;
4848 1648634 : bool pkdeferrable = false;
4849 : MemoryContext oldcxt;
4850 :
4851 : /* Quick exit if we already computed the list. */
4852 1648634 : if (relation->rd_indexvalid)
4853 1413776 : return list_copy(relation->rd_indexlist);
4854 :
4855 : /*
4856 : * We build the list we intend to return (in the caller's context) while
4857 : * doing the scan. After successfully completing the scan, we copy that
4858 : * list into the relcache entry. This avoids cache-context memory leakage
4859 : * if we get some sort of error partway through.
4860 : */
4861 234858 : result = NIL;
4862 :
4863 : /* Prepare to scan pg_index for entries having indrelid = this rel. */
4864 234858 : ScanKeyInit(&skey,
4865 : Anum_pg_index_indrelid,
4866 : BTEqualStrategyNumber, F_OIDEQ,
4867 : ObjectIdGetDatum(RelationGetRelid(relation)));
4868 :
4869 234858 : indrel = table_open(IndexRelationId, AccessShareLock);
4870 234858 : indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
4871 : NULL, 1, &skey);
4872 :
4873 581583 : while (HeapTupleIsValid(htup = systable_getnext(indscan)))
4874 : {
4875 346725 : Form_pg_index index = (Form_pg_index) GETSTRUCT(htup);
4876 :
4877 : /*
4878 : * Ignore any indexes that are currently being dropped. This will
4879 : * prevent them from being searched, inserted into, or considered in
4880 : * HOT-safety decisions. It's unsafe to touch such an index at all
4881 : * since its catalog entries could disappear at any instant.
4882 : */
4883 346725 : if (!index->indislive)
4884 28 : continue;
4885 :
4886 : /* add index's OID to result list */
4887 346697 : result = lappend_oid(result, index->indexrelid);
4888 :
4889 : /*
4890 : * Non-unique or predicate indexes aren't interesting for either oid
4891 : * indexes or replication identity indexes, so don't check them.
4892 : * Deferred ones are not useful for replication identity either; but
4893 : * we do include them if they are PKs.
4894 : */
4895 346697 : if (!index->indisunique ||
4896 298044 : !heap_attisnull(htup, Anum_pg_index_indpred, NULL))
4897 48769 : continue;
4898 :
4899 : /*
4900 : * Remember primary key index, if any. For regular tables we do this
4901 : * only if the index is valid; but for partitioned tables, then we do
4902 : * it even if it's invalid.
4903 : *
4904 : * The reason for returning invalid primary keys for partitioned
4905 : * tables is that we need it to prevent drop of not-null constraints
4906 : * that may underlie such a primary key, which is only a problem for
4907 : * partitioned tables.
4908 : */
4909 297928 : if (index->indisprimary &&
4910 192497 : (index->indisvalid ||
4911 8 : relation->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
4912 : {
4913 192497 : pkeyIndex = index->indexrelid;
4914 192497 : pkdeferrable = !index->indimmediate;
4915 : }
4916 :
4917 297928 : if (!index->indimmediate)
4918 97 : continue;
4919 :
4920 297831 : if (!index->indisvalid)
4921 71 : continue;
4922 :
4923 : /* remember explicitly chosen replica index */
4924 297760 : if (index->indisreplident)
4925 333 : candidateIndex = index->indexrelid;
4926 : }
4927 :
4928 234858 : systable_endscan(indscan);
4929 :
4930 234858 : table_close(indrel, AccessShareLock);
4931 :
4932 : /* Sort the result list into OID order, per API spec. */
4933 234858 : list_sort(result, list_oid_cmp);
4934 :
4935 : /* Now save a copy of the completed list in the relcache entry. */
4936 234858 : oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
4937 234858 : oldlist = relation->rd_indexlist;
4938 234858 : relation->rd_indexlist = list_copy(result);
4939 234858 : relation->rd_pkindex = pkeyIndex;
4940 234858 : relation->rd_ispkdeferrable = pkdeferrable;
4941 234858 : if (replident == REPLICA_IDENTITY_DEFAULT && OidIsValid(pkeyIndex) && !pkdeferrable)
4942 16737 : relation->rd_replidindex = pkeyIndex;
4943 218121 : else if (replident == REPLICA_IDENTITY_INDEX && OidIsValid(candidateIndex))
4944 333 : relation->rd_replidindex = candidateIndex;
4945 : else
4946 217788 : relation->rd_replidindex = InvalidOid;
4947 234858 : relation->rd_indexvalid = true;
4948 234858 : MemoryContextSwitchTo(oldcxt);
4949 :
4950 : /* Don't leak the old list, if there is one */
4951 234858 : list_free(oldlist);
4952 :
4953 234858 : return result;
4954 : }
4955 :
4956 : /*
4957 : * RelationGetStatExtList
4958 : * get a list of OIDs of statistics objects on this relation
4959 : *
4960 : * The statistics list is created only if someone requests it, in a way
4961 : * similar to RelationGetIndexList(). We scan pg_statistic_ext to find
4962 : * relevant statistics, and add the list to the relcache entry so that we
4963 : * won't have to compute it again. Note that shared cache inval of a
4964 : * relcache entry will delete the old list and set rd_statvalid to 0,
4965 : * so that we must recompute the statistics list on next request. This
4966 : * handles creation or deletion of a statistics object.
4967 : *
4968 : * The returned list is guaranteed to be sorted in order by OID, although
4969 : * this is not currently needed.
4970 : *
4971 : * Since shared cache inval causes the relcache's copy of the list to go away,
4972 : * we return a copy of the list palloc'd in the caller's context. The caller
4973 : * may list_free() the returned list after scanning it. This is necessary
4974 : * since the caller will typically be doing syscache lookups on the relevant
4975 : * statistics, and syscache lookup could cause SI messages to be processed!
4976 : */
4977 : List *
4978 373953 : RelationGetStatExtList(Relation relation)
4979 : {
4980 : Relation indrel;
4981 : SysScanDesc indscan;
4982 : ScanKeyData skey;
4983 : HeapTuple htup;
4984 : List *result;
4985 : List *oldlist;
4986 : MemoryContext oldcxt;
4987 :
4988 : /* Quick exit if we already computed the list. */
4989 373953 : if (relation->rd_statvalid != 0)
4990 299204 : return list_copy(relation->rd_statlist);
4991 :
4992 : /*
4993 : * We build the list we intend to return (in the caller's context) while
4994 : * doing the scan. After successfully completing the scan, we copy that
4995 : * list into the relcache entry. This avoids cache-context memory leakage
4996 : * if we get some sort of error partway through.
4997 : */
4998 74749 : result = NIL;
4999 :
5000 : /*
5001 : * Prepare to scan pg_statistic_ext for entries having stxrelid = this
5002 : * rel.
5003 : */
5004 74749 : ScanKeyInit(&skey,
5005 : Anum_pg_statistic_ext_stxrelid,
5006 : BTEqualStrategyNumber, F_OIDEQ,
5007 : ObjectIdGetDatum(RelationGetRelid(relation)));
5008 :
5009 74749 : indrel = table_open(StatisticExtRelationId, AccessShareLock);
5010 74749 : indscan = systable_beginscan(indrel, StatisticExtRelidIndexId, true,
5011 : NULL, 1, &skey);
5012 :
5013 75071 : while (HeapTupleIsValid(htup = systable_getnext(indscan)))
5014 : {
5015 322 : Oid oid = ((Form_pg_statistic_ext) GETSTRUCT(htup))->oid;
5016 :
5017 322 : result = lappend_oid(result, oid);
5018 : }
5019 :
5020 74749 : systable_endscan(indscan);
5021 :
5022 74749 : table_close(indrel, AccessShareLock);
5023 :
5024 : /* Sort the result list into OID order, per API spec. */
5025 74749 : list_sort(result, list_oid_cmp);
5026 :
5027 : /* Now save a copy of the completed list in the relcache entry. */
5028 74749 : oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
5029 74749 : oldlist = relation->rd_statlist;
5030 74749 : relation->rd_statlist = list_copy(result);
5031 :
5032 74749 : relation->rd_statvalid = true;
5033 74749 : MemoryContextSwitchTo(oldcxt);
5034 :
5035 : /* Don't leak the old list, if there is one */
5036 74749 : list_free(oldlist);
5037 :
5038 74749 : return result;
5039 : }
5040 :
5041 : /*
5042 : * RelationGetPrimaryKeyIndex -- get OID of the relation's primary key index
5043 : *
5044 : * Returns InvalidOid if there is no such index, or if the primary key is
5045 : * DEFERRABLE and the caller isn't OK with that.
5046 : */
5047 : Oid
5048 388 : RelationGetPrimaryKeyIndex(Relation relation, bool deferrable_ok)
5049 : {
5050 : List *ilist;
5051 :
5052 388 : if (!relation->rd_indexvalid)
5053 : {
5054 : /* RelationGetIndexList does the heavy lifting. */
5055 64 : ilist = RelationGetIndexList(relation);
5056 64 : list_free(ilist);
5057 : Assert(relation->rd_indexvalid);
5058 : }
5059 :
5060 388 : if (deferrable_ok)
5061 12 : return relation->rd_pkindex;
5062 376 : else if (relation->rd_ispkdeferrable)
5063 4 : return InvalidOid;
5064 372 : return relation->rd_pkindex;
5065 : }
5066 :
5067 : /*
5068 : * RelationGetReplicaIndex -- get OID of the relation's replica identity index
5069 : *
5070 : * Returns InvalidOid if there is no such index.
5071 : */
5072 : Oid
5073 166541 : RelationGetReplicaIndex(Relation relation)
5074 : {
5075 : List *ilist;
5076 :
5077 166541 : if (!relation->rd_indexvalid)
5078 : {
5079 : /* RelationGetIndexList does the heavy lifting. */
5080 3635 : ilist = RelationGetIndexList(relation);
5081 3635 : list_free(ilist);
5082 : Assert(relation->rd_indexvalid);
5083 : }
5084 :
5085 166541 : return relation->rd_replidindex;
5086 : }
5087 :
5088 : /*
5089 : * RelationGetIndexExpressions -- get the index expressions for an index
5090 : *
5091 : * We cache the result of transforming pg_index.indexprs into a node tree.
5092 : * If the rel is not an index or has no expressional columns, we return NIL.
5093 : * Otherwise, the returned tree is copied into the caller's memory context.
5094 : * (We don't want to return a pointer to the relcache copy, since it could
5095 : * disappear due to relcache invalidation.)
5096 : */
5097 : List *
5098 2942084 : RelationGetIndexExpressions(Relation relation)
5099 : {
5100 : List *result;
5101 : Datum exprsDatum;
5102 : bool isnull;
5103 : char *exprsString;
5104 : MemoryContext oldcxt;
5105 :
5106 : /* Quick exit if we already computed the result. */
5107 2942084 : if (relation->rd_indexprs)
5108 2868 : return copyObject(relation->rd_indexprs);
5109 :
5110 : /* Quick exit if there is nothing to do. */
5111 5878432 : if (relation->rd_indextuple == NULL ||
5112 2939216 : heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5113 2937960 : return NIL;
5114 :
5115 : /*
5116 : * We build the tree we intend to return in the caller's context. After
5117 : * successfully completing the work, we copy it into the relcache entry.
5118 : * This avoids problems if we get some sort of error partway through.
5119 : */
5120 1256 : exprsDatum = heap_getattr(relation->rd_indextuple,
5121 : Anum_pg_index_indexprs,
5122 : GetPgIndexDescriptor(),
5123 : &isnull);
5124 : Assert(!isnull);
5125 1256 : exprsString = TextDatumGetCString(exprsDatum);
5126 1256 : result = (List *) stringToNode(exprsString);
5127 1256 : pfree(exprsString);
5128 :
5129 : /*
5130 : * Run the expressions through eval_const_expressions. This is not just an
5131 : * optimization, but is necessary, because the planner will be comparing
5132 : * them to similarly-processed qual clauses, and may fail to detect valid
5133 : * matches without this. We must not use canonicalize_qual, however,
5134 : * since these aren't qual expressions.
5135 : */
5136 1256 : result = (List *) eval_const_expressions(NULL, (Node *) result);
5137 :
5138 : /* May as well fix opfuncids too */
5139 1256 : fix_opfuncids((Node *) result);
5140 :
5141 : /* Now save a copy of the completed tree in the relcache entry. */
5142 1256 : oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5143 1256 : relation->rd_indexprs = copyObject(result);
5144 1256 : MemoryContextSwitchTo(oldcxt);
5145 :
5146 1256 : return result;
5147 : }
5148 :
5149 : /*
5150 : * RelationGetDummyIndexExpressions -- get dummy expressions for an index
5151 : *
5152 : * Return a list of dummy expressions (just Const nodes) with the same
5153 : * types/typmods/collations as the index's real expressions. This is
5154 : * useful in situations where we don't want to run any user-defined code.
5155 : */
5156 : List *
5157 175 : RelationGetDummyIndexExpressions(Relation relation)
5158 : {
5159 : List *result;
5160 : Datum exprsDatum;
5161 : bool isnull;
5162 : char *exprsString;
5163 : List *rawExprs;
5164 : ListCell *lc;
5165 :
5166 : /* Quick exit if there is nothing to do. */
5167 350 : if (relation->rd_indextuple == NULL ||
5168 175 : heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs, NULL))
5169 139 : return NIL;
5170 :
5171 : /* Extract raw node tree(s) from index tuple. */
5172 36 : exprsDatum = heap_getattr(relation->rd_indextuple,
5173 : Anum_pg_index_indexprs,
5174 : GetPgIndexDescriptor(),
5175 : &isnull);
5176 : Assert(!isnull);
5177 36 : exprsString = TextDatumGetCString(exprsDatum);
5178 36 : rawExprs = (List *) stringToNode(exprsString);
5179 36 : pfree(exprsString);
5180 :
5181 : /* Construct null Consts; the typlen and typbyval are arbitrary. */
5182 36 : result = NIL;
5183 72 : foreach(lc, rawExprs)
5184 : {
5185 36 : Node *rawExpr = (Node *) lfirst(lc);
5186 :
5187 36 : result = lappend(result,
5188 36 : makeConst(exprType(rawExpr),
5189 : exprTypmod(rawExpr),
5190 : exprCollation(rawExpr),
5191 : 1,
5192 : (Datum) 0,
5193 : true,
5194 : true));
5195 : }
5196 :
5197 36 : return result;
5198 : }
5199 :
5200 : /*
5201 : * RelationGetIndexPredicate -- get the index predicate for an index
5202 : *
5203 : * We cache the result of transforming pg_index.indpred into an implicit-AND
5204 : * node tree (suitable for use in planning).
5205 : * If the rel is not an index or has no predicate, we return NIL.
5206 : * Otherwise, the returned tree is copied into the caller's memory context.
5207 : * (We don't want to return a pointer to the relcache copy, since it could
5208 : * disappear due to relcache invalidation.)
5209 : */
5210 : List *
5211 2941947 : RelationGetIndexPredicate(Relation relation)
5212 : {
5213 : List *result;
5214 : Datum predDatum;
5215 : bool isnull;
5216 : char *predString;
5217 : MemoryContext oldcxt;
5218 :
5219 : /* Quick exit if we already computed the result. */
5220 2941947 : if (relation->rd_indpred)
5221 1050 : return copyObject(relation->rd_indpred);
5222 :
5223 : /* Quick exit if there is nothing to do. */
5224 5881794 : if (relation->rd_indextuple == NULL ||
5225 2940897 : heap_attisnull(relation->rd_indextuple, Anum_pg_index_indpred, NULL))
5226 2940262 : return NIL;
5227 :
5228 : /*
5229 : * We build the tree we intend to return in the caller's context. After
5230 : * successfully completing the work, we copy it into the relcache entry.
5231 : * This avoids problems if we get some sort of error partway through.
5232 : */
5233 635 : predDatum = heap_getattr(relation->rd_indextuple,
5234 : Anum_pg_index_indpred,
5235 : GetPgIndexDescriptor(),
5236 : &isnull);
5237 : Assert(!isnull);
5238 635 : predString = TextDatumGetCString(predDatum);
5239 635 : result = (List *) stringToNode(predString);
5240 635 : pfree(predString);
5241 :
5242 : /*
5243 : * Run the expression through const-simplification and canonicalization.
5244 : * This is not just an optimization, but is necessary, because the planner
5245 : * will be comparing it to similarly-processed qual clauses, and may fail
5246 : * to detect valid matches without this. This must match the processing
5247 : * done to qual clauses in preprocess_expression()! (We can skip the
5248 : * stuff involving subqueries, however, since we don't allow any in index
5249 : * predicates.)
5250 : */
5251 635 : result = (List *) eval_const_expressions(NULL, (Node *) result);
5252 :
5253 635 : result = (List *) canonicalize_qual((Expr *) result, false);
5254 :
5255 : /* Also convert to implicit-AND format */
5256 635 : result = make_ands_implicit((Expr *) result);
5257 :
5258 : /* May as well fix opfuncids too */
5259 635 : fix_opfuncids((Node *) result);
5260 :
5261 : /* Now save a copy of the completed tree in the relcache entry. */
5262 635 : oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
5263 635 : relation->rd_indpred = copyObject(result);
5264 635 : MemoryContextSwitchTo(oldcxt);
5265 :
5266 635 : return result;
5267 : }
5268 :
5269 : /*
5270 : * RelationGetIndexAttrBitmap -- get a bitmap of index attribute numbers
5271 : *
5272 : * The result has a bit set for each attribute used anywhere in the index
5273 : * definitions of all the indexes on this relation. (This includes not only
5274 : * simple index keys, but attributes used in expressions and partial-index
5275 : * predicates.)
5276 : *
5277 : * Depending on attrKind, a bitmap covering attnums for certain columns is
5278 : * returned:
5279 : * INDEX_ATTR_BITMAP_KEY Columns in non-partial unique indexes not
5280 : * in expressions (i.e., usable for FKs)
5281 : * INDEX_ATTR_BITMAP_PRIMARY_KEY Columns in the table's primary key
5282 : * (beware: even if PK is deferrable!)
5283 : * INDEX_ATTR_BITMAP_IDENTITY_KEY Columns in the table's replica identity
5284 : * index (empty if FULL)
5285 : * INDEX_ATTR_BITMAP_HOT_BLOCKING Columns that block updates from being HOT
5286 : * INDEX_ATTR_BITMAP_SUMMARIZED Columns included in summarizing indexes
5287 : *
5288 : * Attribute numbers are offset by FirstLowInvalidHeapAttributeNumber so that
5289 : * we can include system attributes (e.g., OID) in the bitmap representation.
5290 : *
5291 : * Deferred indexes are considered for the primary key, but not for replica
5292 : * identity.
5293 : *
5294 : * Caller had better hold at least RowExclusiveLock on the target relation
5295 : * to ensure it is safe (deadlock-free) for us to take locks on the relation's
5296 : * indexes. Note that since the introduction of CREATE INDEX CONCURRENTLY,
5297 : * that lock level doesn't guarantee a stable set of indexes, so we have to
5298 : * be prepared to retry here in case of a change in the set of indexes.
5299 : *
5300 : * The returned result is palloc'd in the caller's memory context and should
5301 : * be bms_free'd when not needed anymore.
5302 : */
5303 : Bitmapset *
5304 9696378 : RelationGetIndexAttrBitmap(Relation relation, IndexAttrBitmapKind attrKind)
5305 : {
5306 : Bitmapset *uindexattrs; /* columns in unique indexes */
5307 : Bitmapset *pkindexattrs; /* columns in the primary index */
5308 : Bitmapset *idindexattrs; /* columns in the replica identity */
5309 : Bitmapset *hotblockingattrs; /* columns with HOT blocking indexes */
5310 : Bitmapset *summarizedattrs; /* columns with summarizing indexes */
5311 : List *indexoidlist;
5312 : List *newindexoidlist;
5313 : Oid relpkindex;
5314 : Oid relreplindex;
5315 : ListCell *l;
5316 : MemoryContext oldcxt;
5317 :
5318 : /* Quick exit if we already computed the result. */
5319 9696378 : if (relation->rd_attrsvalid)
5320 : {
5321 1393875 : switch (attrKind)
5322 : {
5323 341198 : case INDEX_ATTR_BITMAP_KEY:
5324 341198 : return bms_copy(relation->rd_keyattr);
5325 39 : case INDEX_ATTR_BITMAP_PRIMARY_KEY:
5326 39 : return bms_copy(relation->rd_pkattr);
5327 384875 : case INDEX_ATTR_BITMAP_IDENTITY_KEY:
5328 384875 : return bms_copy(relation->rd_idattr);
5329 330067 : case INDEX_ATTR_BITMAP_HOT_BLOCKING:
5330 330067 : return bms_copy(relation->rd_hotblockingattr);
5331 337696 : case INDEX_ATTR_BITMAP_SUMMARIZED:
5332 337696 : return bms_copy(relation->rd_summarizedattr);
5333 0 : default:
5334 0 : elog(ERROR, "unknown attrKind %u", attrKind);
5335 : }
5336 : }
5337 :
5338 : /* Fast path if definitely no indexes */
5339 8302503 : if (!RelationGetForm(relation)->relhasindex)
5340 8292527 : return NULL;
5341 :
5342 : /*
5343 : * Get cached list of index OIDs. If we have to start over, we do so here.
5344 : */
5345 9976 : restart:
5346 9982 : indexoidlist = RelationGetIndexList(relation);
5347 :
5348 : /* Fall out if no indexes (but relhasindex was set) */
5349 9982 : if (indexoidlist == NIL)
5350 750 : return NULL;
5351 :
5352 : /*
5353 : * Copy the rd_pkindex and rd_replidindex values computed by
5354 : * RelationGetIndexList before proceeding. This is needed because a
5355 : * relcache flush could occur inside index_open below, resetting the
5356 : * fields managed by RelationGetIndexList. We need to do the work with
5357 : * stable values of these fields.
5358 : */
5359 9232 : relpkindex = relation->rd_pkindex;
5360 9232 : relreplindex = relation->rd_replidindex;
5361 :
5362 : /*
5363 : * For each index, add referenced attributes to indexattrs.
5364 : *
5365 : * Note: we consider all indexes returned by RelationGetIndexList, even if
5366 : * they are not indisready or indisvalid. This is important because an
5367 : * index for which CREATE INDEX CONCURRENTLY has just started must be
5368 : * included in HOT-safety decisions (see README.HOT). If a DROP INDEX
5369 : * CONCURRENTLY is far enough along that we should ignore the index, it
5370 : * won't be returned at all by RelationGetIndexList.
5371 : */
5372 9232 : uindexattrs = NULL;
5373 9232 : pkindexattrs = NULL;
5374 9232 : idindexattrs = NULL;
5375 9232 : hotblockingattrs = NULL;
5376 9232 : summarizedattrs = NULL;
5377 26002 : foreach(l, indexoidlist)
5378 : {
5379 16770 : Oid indexOid = lfirst_oid(l);
5380 : Relation indexDesc;
5381 : Datum datum;
5382 : bool isnull;
5383 : Node *indexExpressions;
5384 : Node *indexPredicate;
5385 : int i;
5386 : bool isKey; /* candidate key */
5387 : bool isPK; /* primary key */
5388 : bool isIDKey; /* replica identity index */
5389 : Bitmapset **attrs;
5390 :
5391 16770 : indexDesc = index_open(indexOid, AccessShareLock);
5392 :
5393 : /*
5394 : * Extract index expressions and index predicate. Note: Don't use
5395 : * RelationGetIndexExpressions()/RelationGetIndexPredicate(), because
5396 : * those might run constant expressions evaluation, which needs a
5397 : * snapshot, which we might not have here. (Also, it's probably more
5398 : * sound to collect the bitmaps before any transformations that might
5399 : * eliminate columns, but the practical impact of this is limited.)
5400 : */
5401 :
5402 16770 : datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indexprs,
5403 : GetPgIndexDescriptor(), &isnull);
5404 16770 : if (!isnull)
5405 28 : indexExpressions = stringToNode(TextDatumGetCString(datum));
5406 : else
5407 16742 : indexExpressions = NULL;
5408 :
5409 16770 : datum = heap_getattr(indexDesc->rd_indextuple, Anum_pg_index_indpred,
5410 : GetPgIndexDescriptor(), &isnull);
5411 16770 : if (!isnull)
5412 59 : indexPredicate = stringToNode(TextDatumGetCString(datum));
5413 : else
5414 16711 : indexPredicate = NULL;
5415 :
5416 : /* Can this index be referenced by a foreign key? */
5417 13216 : isKey = indexDesc->rd_index->indisunique &&
5418 29986 : indexExpressions == NULL &&
5419 : indexPredicate == NULL;
5420 :
5421 : /* Is this a primary key? */
5422 16770 : isPK = (indexOid == relpkindex);
5423 :
5424 : /* Is this index the configured (or default) replica identity? */
5425 16770 : isIDKey = (indexOid == relreplindex);
5426 :
5427 : /*
5428 : * If the index is summarizing, it doesn't block HOT updates, but we
5429 : * may still need to update it (if the attributes were modified). So
5430 : * decide which bitmap we'll update in the following loop.
5431 : */
5432 16770 : if (indexDesc->rd_indam->amsummarizing)
5433 48 : attrs = &summarizedattrs;
5434 : else
5435 16722 : attrs = &hotblockingattrs;
5436 :
5437 : /* Collect simple attribute references */
5438 43135 : for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5439 : {
5440 26365 : int attrnum = indexDesc->rd_index->indkey.values[i];
5441 :
5442 : /*
5443 : * Since we have covering indexes with non-key columns, we must
5444 : * handle them accurately here. non-key columns must be added into
5445 : * hotblockingattrs or summarizedattrs, since they are in index,
5446 : * and update shouldn't miss them.
5447 : *
5448 : * Summarizing indexes do not block HOT, but do need to be updated
5449 : * when the column value changes, thus require a separate
5450 : * attribute bitmapset.
5451 : *
5452 : * Obviously, non-key columns couldn't be referenced by foreign
5453 : * key or identity key. Hence we do not include them into
5454 : * uindexattrs, pkindexattrs and idindexattrs bitmaps.
5455 : */
5456 26365 : if (attrnum != 0)
5457 : {
5458 26337 : *attrs = bms_add_member(*attrs,
5459 : attrnum - FirstLowInvalidHeapAttributeNumber);
5460 :
5461 26337 : if (isKey && i < indexDesc->rd_index->indnkeyatts)
5462 19779 : uindexattrs = bms_add_member(uindexattrs,
5463 : attrnum - FirstLowInvalidHeapAttributeNumber);
5464 :
5465 26337 : if (isPK && i < indexDesc->rd_index->indnkeyatts)
5466 10101 : pkindexattrs = bms_add_member(pkindexattrs,
5467 : attrnum - FirstLowInvalidHeapAttributeNumber);
5468 :
5469 26337 : if (isIDKey && i < indexDesc->rd_index->indnkeyatts)
5470 2970 : idindexattrs = bms_add_member(idindexattrs,
5471 : attrnum - FirstLowInvalidHeapAttributeNumber);
5472 : }
5473 : }
5474 :
5475 : /* Collect all attributes used in expressions, too */
5476 16770 : pull_varattnos(indexExpressions, 1, attrs);
5477 :
5478 : /* Collect all attributes in the index predicate, too */
5479 16770 : pull_varattnos(indexPredicate, 1, attrs);
5480 :
5481 16770 : index_close(indexDesc, AccessShareLock);
5482 : }
5483 :
5484 : /*
5485 : * During one of the index_opens in the above loop, we might have received
5486 : * a relcache flush event on this relcache entry, which might have been
5487 : * signaling a change in the rel's index list. If so, we'd better start
5488 : * over to ensure we deliver up-to-date attribute bitmaps.
5489 : */
5490 9232 : newindexoidlist = RelationGetIndexList(relation);
5491 9232 : if (equal(indexoidlist, newindexoidlist) &&
5492 9229 : relpkindex == relation->rd_pkindex &&
5493 9226 : relreplindex == relation->rd_replidindex)
5494 : {
5495 : /* Still the same index set, so proceed */
5496 9226 : list_free(newindexoidlist);
5497 9226 : list_free(indexoidlist);
5498 : }
5499 : else
5500 : {
5501 : /* Gotta do it over ... might as well not leak memory */
5502 6 : list_free(newindexoidlist);
5503 6 : list_free(indexoidlist);
5504 6 : bms_free(uindexattrs);
5505 6 : bms_free(pkindexattrs);
5506 6 : bms_free(idindexattrs);
5507 6 : bms_free(hotblockingattrs);
5508 6 : bms_free(summarizedattrs);
5509 :
5510 6 : goto restart;
5511 : }
5512 :
5513 : /* Don't leak the old values of these bitmaps, if any */
5514 9226 : relation->rd_attrsvalid = false;
5515 9226 : bms_free(relation->rd_keyattr);
5516 9226 : relation->rd_keyattr = NULL;
5517 9226 : bms_free(relation->rd_pkattr);
5518 9226 : relation->rd_pkattr = NULL;
5519 9226 : bms_free(relation->rd_idattr);
5520 9226 : relation->rd_idattr = NULL;
5521 9226 : bms_free(relation->rd_hotblockingattr);
5522 9226 : relation->rd_hotblockingattr = NULL;
5523 9226 : bms_free(relation->rd_summarizedattr);
5524 9226 : relation->rd_summarizedattr = NULL;
5525 :
5526 : /*
5527 : * Now save copies of the bitmaps in the relcache entry. We intentionally
5528 : * set rd_attrsvalid last, because that's the one that signals validity of
5529 : * the values; if we run out of memory before making that copy, we won't
5530 : * leave the relcache entry looking like the other ones are valid but
5531 : * empty.
5532 : */
5533 9226 : oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
5534 9226 : relation->rd_keyattr = bms_copy(uindexattrs);
5535 9226 : relation->rd_pkattr = bms_copy(pkindexattrs);
5536 9226 : relation->rd_idattr = bms_copy(idindexattrs);
5537 9226 : relation->rd_hotblockingattr = bms_copy(hotblockingattrs);
5538 9226 : relation->rd_summarizedattr = bms_copy(summarizedattrs);
5539 9226 : relation->rd_attrsvalid = true;
5540 9226 : MemoryContextSwitchTo(oldcxt);
5541 :
5542 : /* We return our original working copy for caller to play with */
5543 9226 : switch (attrKind)
5544 : {
5545 796 : case INDEX_ATTR_BITMAP_KEY:
5546 796 : return uindexattrs;
5547 32 : case INDEX_ATTR_BITMAP_PRIMARY_KEY:
5548 32 : return pkindexattrs;
5549 769 : case INDEX_ATTR_BITMAP_IDENTITY_KEY:
5550 769 : return idindexattrs;
5551 7629 : case INDEX_ATTR_BITMAP_HOT_BLOCKING:
5552 7629 : return hotblockingattrs;
5553 0 : case INDEX_ATTR_BITMAP_SUMMARIZED:
5554 0 : return summarizedattrs;
5555 0 : default:
5556 0 : elog(ERROR, "unknown attrKind %u", attrKind);
5557 : return NULL;
5558 : }
5559 : }
5560 :
5561 : /*
5562 : * RelationGetIdentityKeyBitmap -- get a bitmap of replica identity attribute
5563 : * numbers
5564 : *
5565 : * A bitmap of index attribute numbers for the configured replica identity
5566 : * index is returned.
5567 : *
5568 : * See also comments of RelationGetIndexAttrBitmap().
5569 : *
5570 : * This is a special purpose function used during logical replication. Here,
5571 : * unlike RelationGetIndexAttrBitmap(), we don't acquire a lock on the required
5572 : * index as we build the cache entry using a historic snapshot and all the
5573 : * later changes are absorbed while decoding WAL. Due to this reason, we don't
5574 : * need to retry here in case of a change in the set of indexes.
5575 : */
5576 : Bitmapset *
5577 371 : RelationGetIdentityKeyBitmap(Relation relation)
5578 : {
5579 371 : Bitmapset *idindexattrs = NULL; /* columns in the replica identity */
5580 : Relation indexDesc;
5581 : int i;
5582 : Oid replidindex;
5583 : MemoryContext oldcxt;
5584 :
5585 : /* Quick exit if we already computed the result */
5586 371 : if (relation->rd_idattr != NULL)
5587 47 : return bms_copy(relation->rd_idattr);
5588 :
5589 : /* Fast path if definitely no indexes */
5590 324 : if (!RelationGetForm(relation)->relhasindex)
5591 75 : return NULL;
5592 :
5593 : /* Historic snapshot must be set. */
5594 : Assert(HistoricSnapshotActive());
5595 :
5596 249 : replidindex = RelationGetReplicaIndex(relation);
5597 :
5598 : /* Fall out if there is no replica identity index */
5599 249 : if (!OidIsValid(replidindex))
5600 5 : return NULL;
5601 :
5602 : /* Look up the description for the replica identity index */
5603 244 : indexDesc = RelationIdGetRelation(replidindex);
5604 :
5605 244 : if (!RelationIsValid(indexDesc))
5606 0 : elog(ERROR, "could not open relation with OID %u",
5607 : relation->rd_replidindex);
5608 :
5609 : /* Add referenced attributes to idindexattrs */
5610 495 : for (i = 0; i < indexDesc->rd_index->indnatts; i++)
5611 : {
5612 251 : int attrnum = indexDesc->rd_index->indkey.values[i];
5613 :
5614 : /*
5615 : * We don't include non-key columns into idindexattrs bitmaps. See
5616 : * RelationGetIndexAttrBitmap.
5617 : */
5618 251 : if (attrnum != 0)
5619 : {
5620 251 : if (i < indexDesc->rd_index->indnkeyatts)
5621 250 : idindexattrs = bms_add_member(idindexattrs,
5622 : attrnum - FirstLowInvalidHeapAttributeNumber);
5623 : }
5624 : }
5625 :
5626 244 : RelationClose(indexDesc);
5627 :
5628 : /* Don't leak the old values of these bitmaps, if any */
5629 244 : bms_free(relation->rd_idattr);
5630 244 : relation->rd_idattr = NULL;
5631 :
5632 : /* Now save copy of the bitmap in the relcache entry */
5633 244 : oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
5634 244 : relation->rd_idattr = bms_copy(idindexattrs);
5635 244 : MemoryContextSwitchTo(oldcxt);
5636 :
5637 : /* We return our original working copy for caller to play with */
5638 244 : return idindexattrs;
5639 : }
5640 :
5641 : /*
5642 : * RelationGetExclusionInfo -- get info about index's exclusion constraint
5643 : *
5644 : * This should be called only for an index that is known to have an associated
5645 : * exclusion constraint or primary key/unique constraint using WITHOUT
5646 : * OVERLAPS.
5647 : *
5648 : * It returns arrays (palloc'd in caller's context) of the exclusion operator
5649 : * OIDs, their underlying functions' OIDs, and their strategy numbers in the
5650 : * index's opclasses. We cache all this information since it requires a fair
5651 : * amount of work to get.
5652 : */
5653 : void
5654 2265 : RelationGetExclusionInfo(Relation indexRelation,
5655 : Oid **operators,
5656 : Oid **procs,
5657 : uint16 **strategies)
5658 : {
5659 : int indnkeyatts;
5660 : Oid *ops;
5661 : Oid *funcs;
5662 : uint16 *strats;
5663 : Relation conrel;
5664 : SysScanDesc conscan;
5665 : ScanKeyData skey[1];
5666 : HeapTuple htup;
5667 : bool found;
5668 : MemoryContext oldcxt;
5669 : int i;
5670 :
5671 2265 : indnkeyatts = IndexRelationGetNumberOfKeyAttributes(indexRelation);
5672 :
5673 : /* Allocate result space in caller context */
5674 2265 : *operators = ops = palloc_array(Oid, indnkeyatts);
5675 2265 : *procs = funcs = palloc_array(Oid, indnkeyatts);
5676 2265 : *strategies = strats = palloc_array(uint16, indnkeyatts);
5677 :
5678 : /* Quick exit if we have the data cached already */
5679 2265 : if (indexRelation->rd_exclstrats != NULL)
5680 : {
5681 1397 : memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * indnkeyatts);
5682 1397 : memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * indnkeyatts);
5683 1397 : memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * indnkeyatts);
5684 1397 : return;
5685 : }
5686 :
5687 : /*
5688 : * Search pg_constraint for the constraint associated with the index. To
5689 : * make this not too painfully slow, we use the index on conrelid; that
5690 : * will hold the parent relation's OID not the index's own OID.
5691 : *
5692 : * Note: if we wanted to rely on the constraint name matching the index's
5693 : * name, we could just do a direct lookup using pg_constraint's unique
5694 : * index. For the moment it doesn't seem worth requiring that.
5695 : */
5696 868 : ScanKeyInit(&skey[0],
5697 : Anum_pg_constraint_conrelid,
5698 : BTEqualStrategyNumber, F_OIDEQ,
5699 868 : ObjectIdGetDatum(indexRelation->rd_index->indrelid));
5700 :
5701 868 : conrel = table_open(ConstraintRelationId, AccessShareLock);
5702 868 : conscan = systable_beginscan(conrel, ConstraintRelidTypidNameIndexId, true,
5703 : NULL, 1, skey);
5704 868 : found = false;
5705 :
5706 3781 : while (HeapTupleIsValid(htup = systable_getnext(conscan)))
5707 : {
5708 2913 : Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(htup);
5709 : Datum val;
5710 : bool isnull;
5711 : ArrayType *arr;
5712 : int nelem;
5713 :
5714 : /* We want the exclusion constraint owning the index */
5715 2913 : if ((conform->contype != CONSTRAINT_EXCLUSION &&
5716 2761 : !(conform->conperiod && (conform->contype == CONSTRAINT_PRIMARY
5717 175 : || conform->contype == CONSTRAINT_UNIQUE))) ||
5718 956 : conform->conindid != RelationGetRelid(indexRelation))
5719 2045 : continue;
5720 :
5721 : /* There should be only one */
5722 868 : if (found)
5723 0 : elog(ERROR, "unexpected exclusion constraint record found for rel %s",
5724 : RelationGetRelationName(indexRelation));
5725 868 : found = true;
5726 :
5727 : /* Extract the operator OIDS from conexclop */
5728 868 : val = fastgetattr(htup,
5729 : Anum_pg_constraint_conexclop,
5730 : conrel->rd_att, &isnull);
5731 868 : if (isnull)
5732 0 : elog(ERROR, "null conexclop for rel %s",
5733 : RelationGetRelationName(indexRelation));
5734 :
5735 868 : arr = DatumGetArrayTypeP(val); /* ensure not toasted */
5736 868 : nelem = ARR_DIMS(arr)[0];
5737 868 : if (ARR_NDIM(arr) != 1 ||
5738 868 : nelem != indnkeyatts ||
5739 868 : ARR_HASNULL(arr) ||
5740 868 : ARR_ELEMTYPE(arr) != OIDOID)
5741 0 : elog(ERROR, "conexclop is not a 1-D Oid array");
5742 :
5743 868 : memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * indnkeyatts);
5744 : }
5745 :
5746 868 : systable_endscan(conscan);
5747 868 : table_close(conrel, AccessShareLock);
5748 :
5749 868 : if (!found)
5750 0 : elog(ERROR, "exclusion constraint record missing for rel %s",
5751 : RelationGetRelationName(indexRelation));
5752 :
5753 : /* We need the func OIDs and strategy numbers too */
5754 2547 : for (i = 0; i < indnkeyatts; i++)
5755 : {
5756 1679 : funcs[i] = get_opcode(ops[i]);
5757 3358 : strats[i] = get_op_opfamily_strategy(ops[i],
5758 1679 : indexRelation->rd_opfamily[i]);
5759 : /* shouldn't fail, since it was checked at index creation */
5760 1679 : if (strats[i] == InvalidStrategy)
5761 0 : elog(ERROR, "could not find strategy for operator %u in family %u",
5762 : ops[i], indexRelation->rd_opfamily[i]);
5763 : }
5764 :
5765 : /* Save a copy of the results in the relcache entry. */
5766 868 : oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
5767 868 : indexRelation->rd_exclops = palloc_array(Oid, indnkeyatts);
5768 868 : indexRelation->rd_exclprocs = palloc_array(Oid, indnkeyatts);
5769 868 : indexRelation->rd_exclstrats = palloc_array(uint16, indnkeyatts);
5770 868 : memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * indnkeyatts);
5771 868 : memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * indnkeyatts);
5772 868 : memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * indnkeyatts);
5773 868 : MemoryContextSwitchTo(oldcxt);
5774 : }
5775 :
5776 : /*
5777 : * Get the publication information for the given relation.
5778 : *
5779 : * Traverse all the publications which the relation is in to get the
5780 : * publication actions and validate:
5781 : * 1. The row filter expressions for such publications if any. We consider the
5782 : * row filter expression as invalid if it references any column which is not
5783 : * part of REPLICA IDENTITY.
5784 : * 2. The column list for such publication if any. We consider the column list
5785 : * invalid if REPLICA IDENTITY contains any column that is not part of it.
5786 : * 3. The generated columns of the relation for such publications. We consider
5787 : * any reference of an unpublished generated column in REPLICA IDENTITY as
5788 : * invalid.
5789 : *
5790 : * To avoid fetching the publication information repeatedly, we cache the
5791 : * publication actions, row filter validation information, column list
5792 : * validation information, and generated column validation information.
5793 : */
5794 : void
5795 93280 : RelationBuildPublicationDesc(Relation relation, PublicationDesc *pubdesc)
5796 : {
5797 93280 : List *puboids = NIL;
5798 93280 : List *exceptpuboids = NIL;
5799 : List *alltablespuboids;
5800 : ListCell *lc;
5801 : MemoryContext oldcxt;
5802 : Oid schemaid;
5803 93280 : List *ancestors = NIL;
5804 93280 : Oid relid = RelationGetRelid(relation);
5805 :
5806 : /*
5807 : * If not publishable, it publishes no actions. (pgoutput_change() will
5808 : * ignore it.)
5809 : */
5810 93280 : if (!is_publishable_relation(relation))
5811 : {
5812 3573 : memset(pubdesc, 0, sizeof(PublicationDesc));
5813 3573 : pubdesc->rf_valid_for_update = true;
5814 3573 : pubdesc->rf_valid_for_delete = true;
5815 3573 : pubdesc->cols_valid_for_update = true;
5816 3573 : pubdesc->cols_valid_for_delete = true;
5817 3573 : pubdesc->gencols_valid_for_update = true;
5818 3573 : pubdesc->gencols_valid_for_delete = true;
5819 3573 : return;
5820 : }
5821 :
5822 89707 : if (relation->rd_pubdesc)
5823 : {
5824 83689 : memcpy(pubdesc, relation->rd_pubdesc, sizeof(PublicationDesc));
5825 83689 : return;
5826 : }
5827 :
5828 6018 : memset(pubdesc, 0, sizeof(PublicationDesc));
5829 6018 : pubdesc->rf_valid_for_update = true;
5830 6018 : pubdesc->rf_valid_for_delete = true;
5831 6018 : pubdesc->cols_valid_for_update = true;
5832 6018 : pubdesc->cols_valid_for_delete = true;
5833 6018 : pubdesc->gencols_valid_for_update = true;
5834 6018 : pubdesc->gencols_valid_for_delete = true;
5835 :
5836 : /* Fetch the publication membership info. */
5837 6018 : puboids = GetRelationIncludedPublications(relid);
5838 6018 : schemaid = RelationGetNamespace(relation);
5839 6018 : puboids = list_concat_unique_oid(puboids, GetSchemaPublications(schemaid));
5840 :
5841 6018 : if (relation->rd_rel->relispartition)
5842 : {
5843 : Oid last_ancestor_relid;
5844 :
5845 : /* Add publications that the ancestors are in too. */
5846 1522 : ancestors = get_partition_ancestors(relid);
5847 1522 : last_ancestor_relid = llast_oid(ancestors);
5848 :
5849 3516 : foreach(lc, ancestors)
5850 : {
5851 1994 : Oid ancestor = lfirst_oid(lc);
5852 :
5853 1994 : puboids = list_concat_unique_oid(puboids,
5854 1994 : GetRelationIncludedPublications(ancestor));
5855 1994 : schemaid = get_rel_namespace(ancestor);
5856 1994 : puboids = list_concat_unique_oid(puboids,
5857 1994 : GetSchemaPublications(schemaid));
5858 : }
5859 :
5860 : /*
5861 : * Only the top-most ancestor can appear in the EXCEPT clause.
5862 : * Therefore, for a partition, exclusion must be evaluated at the
5863 : * top-most ancestor.
5864 : */
5865 1522 : exceptpuboids = GetRelationExcludedPublications(last_ancestor_relid);
5866 : }
5867 : else
5868 : {
5869 : /*
5870 : * For a regular table or a root partitioned table, check exclusion on
5871 : * table itself.
5872 : */
5873 4496 : exceptpuboids = GetRelationExcludedPublications(relid);
5874 : }
5875 :
5876 6018 : alltablespuboids = GetAllTablesPublications();
5877 6018 : puboids = list_concat_unique_oid(puboids,
5878 6018 : list_difference_oid(alltablespuboids,
5879 : exceptpuboids));
5880 6456 : foreach(lc, puboids)
5881 : {
5882 566 : Oid pubid = lfirst_oid(lc);
5883 : HeapTuple tup;
5884 : Form_pg_publication pubform;
5885 : bool invalid_column_list;
5886 : bool invalid_gen_col;
5887 :
5888 566 : tup = SearchSysCache1(PUBLICATIONOID, ObjectIdGetDatum(pubid));
5889 :
5890 566 : if (!HeapTupleIsValid(tup))
5891 0 : elog(ERROR, "cache lookup failed for publication %u", pubid);
5892 :
5893 566 : pubform = (Form_pg_publication) GETSTRUCT(tup);
5894 :
5895 566 : pubdesc->pubactions.pubinsert |= pubform->pubinsert;
5896 566 : pubdesc->pubactions.pubupdate |= pubform->pubupdate;
5897 566 : pubdesc->pubactions.pubdelete |= pubform->pubdelete;
5898 566 : pubdesc->pubactions.pubtruncate |= pubform->pubtruncate;
5899 :
5900 : /*
5901 : * Check if all columns referenced in the filter expression are part
5902 : * of the REPLICA IDENTITY index or not.
5903 : *
5904 : * If the publication is FOR ALL TABLES then it means the table has no
5905 : * row filters and we can skip the validation.
5906 : */
5907 566 : if (!pubform->puballtables &&
5908 870 : (pubform->pubupdate || pubform->pubdelete) &&
5909 434 : pub_rf_contains_invalid_column(pubid, relation, ancestors,
5910 434 : pubform->pubviaroot))
5911 : {
5912 40 : if (pubform->pubupdate)
5913 40 : pubdesc->rf_valid_for_update = false;
5914 40 : if (pubform->pubdelete)
5915 40 : pubdesc->rf_valid_for_delete = false;
5916 : }
5917 :
5918 : /*
5919 : * Check if all columns are part of the REPLICA IDENTITY index or not.
5920 : *
5921 : * Check if all generated columns included in the REPLICA IDENTITY are
5922 : * published.
5923 : */
5924 1130 : if ((pubform->pubupdate || pubform->pubdelete) &&
5925 564 : pub_contains_invalid_column(pubid, relation, ancestors,
5926 564 : pubform->pubviaroot,
5927 564 : pubform->pubgencols,
5928 : &invalid_column_list,
5929 : &invalid_gen_col))
5930 : {
5931 88 : if (pubform->pubupdate)
5932 : {
5933 88 : pubdesc->cols_valid_for_update = !invalid_column_list;
5934 88 : pubdesc->gencols_valid_for_update = !invalid_gen_col;
5935 : }
5936 :
5937 88 : if (pubform->pubdelete)
5938 : {
5939 88 : pubdesc->cols_valid_for_delete = !invalid_column_list;
5940 88 : pubdesc->gencols_valid_for_delete = !invalid_gen_col;
5941 : }
5942 : }
5943 :
5944 566 : ReleaseSysCache(tup);
5945 :
5946 : /*
5947 : * If we know everything is replicated and the row filter is invalid
5948 : * for update and delete, there is no point to check for other
5949 : * publications.
5950 : */
5951 566 : if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5952 563 : pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5953 555 : !pubdesc->rf_valid_for_update && !pubdesc->rf_valid_for_delete)
5954 128 : break;
5955 :
5956 : /*
5957 : * If we know everything is replicated and the column list is invalid
5958 : * for update and delete, there is no point to check for other
5959 : * publications.
5960 : */
5961 526 : if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5962 523 : pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5963 515 : !pubdesc->cols_valid_for_update && !pubdesc->cols_valid_for_delete)
5964 72 : break;
5965 :
5966 : /*
5967 : * If we know everything is replicated and replica identity has an
5968 : * unpublished generated column, there is no point to check for other
5969 : * publications.
5970 : */
5971 454 : if (pubdesc->pubactions.pubinsert && pubdesc->pubactions.pubupdate &&
5972 451 : pubdesc->pubactions.pubdelete && pubdesc->pubactions.pubtruncate &&
5973 443 : !pubdesc->gencols_valid_for_update &&
5974 16 : !pubdesc->gencols_valid_for_delete)
5975 16 : break;
5976 : }
5977 :
5978 6018 : if (relation->rd_pubdesc)
5979 : {
5980 0 : pfree(relation->rd_pubdesc);
5981 0 : relation->rd_pubdesc = NULL;
5982 : }
5983 :
5984 : /* Now save copy of the descriptor in the relcache entry. */
5985 6018 : oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
5986 6018 : relation->rd_pubdesc = palloc_object(PublicationDesc);
5987 6018 : memcpy(relation->rd_pubdesc, pubdesc, sizeof(PublicationDesc));
5988 6018 : MemoryContextSwitchTo(oldcxt);
5989 : }
5990 :
5991 : static bytea **
5992 1025312 : CopyIndexAttOptions(bytea **srcopts, int natts)
5993 : {
5994 1025312 : bytea **opts = palloc_array(bytea *, natts);
5995 :
5996 2880645 : for (int i = 0; i < natts; i++)
5997 : {
5998 1855333 : bytea *opt = srcopts[i];
5999 :
6000 1931347 : opts[i] = !opt ? NULL : (bytea *)
6001 76014 : DatumGetPointer(datumCopy(PointerGetDatum(opt), false, -1));
6002 : }
6003 :
6004 1025312 : return opts;
6005 : }
6006 :
6007 : /*
6008 : * RelationGetIndexAttOptions
6009 : * get AM/opclass-specific options for an index parsed into a binary form
6010 : */
6011 : bytea **
6012 1746439 : RelationGetIndexAttOptions(Relation relation, bool copy)
6013 : {
6014 : MemoryContext oldcxt;
6015 1746439 : bytea **opts = relation->rd_opcoptions;
6016 1746439 : Oid relid = RelationGetRelid(relation);
6017 1746439 : int natts = RelationGetNumberOfAttributes(relation); /* XXX
6018 : * IndexRelationGetNumberOfKeyAttributes */
6019 : int i;
6020 :
6021 : /* Try to copy cached options. */
6022 1746439 : if (opts)
6023 1303042 : return copy ? CopyIndexAttOptions(opts, natts) : opts;
6024 :
6025 : /* Get and parse opclass options. */
6026 443397 : opts = palloc0_array(bytea *, natts);
6027 :
6028 1203024 : for (i = 0; i < natts; i++)
6029 : {
6030 759631 : if (criticalRelcachesBuilt && relid != AttributeRelidNumIndexId)
6031 : {
6032 718935 : Datum attoptions = get_attoptions(relid, i + 1);
6033 :
6034 718935 : opts[i] = index_opclass_options(relation, i + 1, attoptions, false);
6035 :
6036 718931 : if (attoptions != (Datum) 0)
6037 184 : pfree(DatumGetPointer(attoptions));
6038 : }
6039 : }
6040 :
6041 : /* Copy parsed options to the cache. */
6042 443393 : oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
6043 443393 : relation->rd_opcoptions = CopyIndexAttOptions(opts, natts);
6044 443393 : MemoryContextSwitchTo(oldcxt);
6045 :
6046 443393 : if (copy)
6047 0 : return opts;
6048 :
6049 1203020 : for (i = 0; i < natts; i++)
6050 : {
6051 759627 : if (opts[i])
6052 1146 : pfree(opts[i]);
6053 : }
6054 :
6055 443393 : pfree(opts);
6056 :
6057 443393 : return relation->rd_opcoptions;
6058 : }
6059 :
6060 : /*
6061 : * Routines to support ereport() reports of relation-related errors
6062 : *
6063 : * These could have been put into elog.c, but it seems like a module layering
6064 : * violation to have elog.c calling relcache or syscache stuff --- and we
6065 : * definitely don't want elog.h including rel.h. So we put them here.
6066 : */
6067 :
6068 : /*
6069 : * errtable --- stores schema_name and table_name of a table
6070 : * within the current errordata.
6071 : */
6072 : int
6073 2555 : errtable(Relation rel)
6074 : {
6075 2555 : err_generic_string(PG_DIAG_SCHEMA_NAME,
6076 2555 : get_namespace_name(RelationGetNamespace(rel)));
6077 2555 : err_generic_string(PG_DIAG_TABLE_NAME, RelationGetRelationName(rel));
6078 :
6079 2555 : return 0; /* return value does not matter */
6080 : }
6081 :
6082 : /*
6083 : * errtablecol --- stores schema_name, table_name and column_name
6084 : * of a table column within the current errordata.
6085 : *
6086 : * The column is specified by attribute number --- for most callers, this is
6087 : * easier and less error-prone than getting the column name for themselves.
6088 : */
6089 : int
6090 405 : errtablecol(Relation rel, int attnum)
6091 : {
6092 405 : TupleDesc reldesc = RelationGetDescr(rel);
6093 : const char *colname;
6094 :
6095 : /* Use reldesc if it's a user attribute, else consult the catalogs */
6096 405 : if (attnum > 0 && attnum <= reldesc->natts)
6097 405 : colname = NameStr(TupleDescAttr(reldesc, attnum - 1)->attname);
6098 : else
6099 0 : colname = get_attname(RelationGetRelid(rel), attnum, false);
6100 :
6101 405 : return errtablecolname(rel, colname);
6102 : }
6103 :
6104 : /*
6105 : * errtablecolname --- stores schema_name, table_name and column_name
6106 : * of a table column within the current errordata, where the column name is
6107 : * given directly rather than extracted from the relation's catalog data.
6108 : *
6109 : * Don't use this directly unless errtablecol() is inconvenient for some
6110 : * reason. This might possibly be needed during intermediate states in ALTER
6111 : * TABLE, for instance.
6112 : */
6113 : int
6114 405 : errtablecolname(Relation rel, const char *colname)
6115 : {
6116 405 : errtable(rel);
6117 405 : err_generic_string(PG_DIAG_COLUMN_NAME, colname);
6118 :
6119 405 : return 0; /* return value does not matter */
6120 : }
6121 :
6122 : /*
6123 : * errtableconstraint --- stores schema_name, table_name and constraint_name
6124 : * of a table-related constraint within the current errordata.
6125 : */
6126 : int
6127 1811 : errtableconstraint(Relation rel, const char *conname)
6128 : {
6129 1811 : errtable(rel);
6130 1811 : err_generic_string(PG_DIAG_CONSTRAINT_NAME, conname);
6131 :
6132 1811 : return 0; /* return value does not matter */
6133 : }
6134 :
6135 :
6136 : /*
6137 : * load_relcache_init_file, write_relcache_init_file
6138 : *
6139 : * In late 1992, we started regularly having databases with more than
6140 : * a thousand classes in them. With this number of classes, it became
6141 : * critical to do indexed lookups on the system catalogs.
6142 : *
6143 : * Bootstrapping these lookups is very hard. We want to be able to
6144 : * use an index on pg_attribute, for example, but in order to do so,
6145 : * we must have read pg_attribute for the attributes in the index,
6146 : * which implies that we need to use the index.
6147 : *
6148 : * In order to get around the problem, we do the following:
6149 : *
6150 : * + When the database system is initialized (at initdb time), we
6151 : * don't use indexes. We do sequential scans.
6152 : *
6153 : * + When the backend is started up in normal mode, we load an image
6154 : * of the appropriate relation descriptors, in internal format,
6155 : * from an initialization file in the data/base/... directory.
6156 : *
6157 : * + If the initialization file isn't there, then we create the
6158 : * relation descriptors using sequential scans and write 'em to
6159 : * the initialization file for use by subsequent backends.
6160 : *
6161 : * As of Postgres 9.0, there is one local initialization file in each
6162 : * database, plus one shared initialization file for shared catalogs.
6163 : *
6164 : * We could dispense with the initialization files and just build the
6165 : * critical reldescs the hard way on every backend startup, but that
6166 : * slows down backend startup noticeably.
6167 : *
6168 : * We can in fact go further, and save more relcache entries than
6169 : * just the ones that are absolutely critical; this allows us to speed
6170 : * up backend startup by not having to build such entries the hard way.
6171 : * Presently, all the catalog and index entries that are referred to
6172 : * by catcaches are stored in the initialization files.
6173 : *
6174 : * The same mechanism that detects when catcache and relcache entries
6175 : * need to be invalidated (due to catalog updates) also arranges to
6176 : * unlink the initialization files when the contents may be out of date.
6177 : * The files will then be rebuilt during the next backend startup.
6178 : */
6179 :
6180 : /*
6181 : * load_relcache_init_file -- attempt to load cache from the shared
6182 : * or local cache init file
6183 : *
6184 : * If successful, return true and set criticalRelcachesBuilt or
6185 : * criticalSharedRelcachesBuilt to true.
6186 : * If not successful, return false.
6187 : *
6188 : * NOTE: we assume we are already switched into CacheMemoryContext.
6189 : */
6190 : static bool
6191 38926 : load_relcache_init_file(bool shared)
6192 : {
6193 : FILE *fp;
6194 : char initfilename[MAXPGPATH];
6195 : Relation *rels;
6196 : int relno,
6197 : num_rels,
6198 : max_rels,
6199 : nailed_rels,
6200 : nailed_indexes,
6201 : magic;
6202 : int i;
6203 :
6204 38926 : if (shared)
6205 20276 : snprintf(initfilename, sizeof(initfilename), "global/%s",
6206 : RELCACHE_INIT_FILENAME);
6207 : else
6208 18650 : snprintf(initfilename, sizeof(initfilename), "%s/%s",
6209 : DatabasePath, RELCACHE_INIT_FILENAME);
6210 :
6211 38926 : fp = AllocateFile(initfilename, PG_BINARY_R);
6212 38926 : if (fp == NULL)
6213 4440 : return false;
6214 :
6215 : /*
6216 : * Read the index relcache entries from the file. Note we will not enter
6217 : * any of them into the cache if the read fails partway through; this
6218 : * helps to guard against broken init files.
6219 : */
6220 34486 : max_rels = 100;
6221 34486 : rels = (Relation *) palloc(max_rels * sizeof(Relation));
6222 34486 : num_rels = 0;
6223 34486 : nailed_rels = nailed_indexes = 0;
6224 :
6225 : /* check for correct magic number (compatible version) */
6226 34486 : if (fread(&magic, 1, sizeof(magic), fp) != sizeof(magic))
6227 0 : goto read_failed;
6228 34486 : if (magic != RELCACHE_INIT_FILEMAGIC)
6229 0 : goto read_failed;
6230 :
6231 34486 : for (relno = 0;; relno++)
6232 2540870 : {
6233 : Size len;
6234 : size_t nread;
6235 : Relation rel;
6236 : Form_pg_class relform;
6237 : bool has_not_null;
6238 :
6239 : /* first read the relation descriptor length */
6240 2575356 : nread = fread(&len, 1, sizeof(len), fp);
6241 2575356 : if (nread != sizeof(len))
6242 : {
6243 34486 : if (nread == 0)
6244 34486 : break; /* end of file */
6245 0 : goto read_failed;
6246 : }
6247 :
6248 : /* safety check for incompatible relcache layout */
6249 2540870 : if (len != sizeof(RelationData))
6250 0 : goto read_failed;
6251 :
6252 : /* allocate another relcache header */
6253 2540870 : if (num_rels >= max_rels)
6254 : {
6255 16813 : max_rels *= 2;
6256 16813 : rels = (Relation *) repalloc(rels, max_rels * sizeof(Relation));
6257 : }
6258 :
6259 2540870 : rel = rels[num_rels++] = (Relation) palloc(len);
6260 :
6261 : /* then, read the Relation structure */
6262 2540870 : if (fread(rel, 1, len, fp) != len)
6263 0 : goto read_failed;
6264 :
6265 : /* next read the relation tuple form */
6266 2540870 : if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6267 0 : goto read_failed;
6268 :
6269 2540870 : relform = (Form_pg_class) palloc(len);
6270 2540870 : if (fread(relform, 1, len, fp) != len)
6271 0 : goto read_failed;
6272 :
6273 2540870 : rel->rd_rel = relform;
6274 :
6275 : /* initialize attribute tuple forms */
6276 2540870 : rel->rd_att = CreateTemplateTupleDesc(relform->relnatts);
6277 2540870 : rel->rd_att->tdrefcount = 1; /* mark as refcounted */
6278 :
6279 2540870 : rel->rd_att->tdtypeid = relform->reltype ? relform->reltype : RECORDOID;
6280 2540870 : rel->rd_att->tdtypmod = -1; /* just to be sure */
6281 :
6282 : /* next read all the attribute tuple form data entries */
6283 2540870 : has_not_null = false;
6284 14778369 : for (i = 0; i < relform->relnatts; i++)
6285 : {
6286 12237499 : Form_pg_attribute attr = TupleDescAttr(rel->rd_att, i);
6287 :
6288 12237499 : if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6289 0 : goto read_failed;
6290 12237499 : if (len != ATTRIBUTE_FIXED_PART_SIZE)
6291 0 : goto read_failed;
6292 12237499 : if (fread(attr, 1, len, fp) != len)
6293 0 : goto read_failed;
6294 :
6295 12237499 : has_not_null |= attr->attnotnull;
6296 :
6297 12237499 : populate_compact_attribute(rel->rd_att, i);
6298 : }
6299 :
6300 2540870 : TupleDescFinalize(rel->rd_att);
6301 :
6302 : /* next read the access method specific field */
6303 2540870 : if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6304 0 : goto read_failed;
6305 2540870 : if (len > 0)
6306 : {
6307 0 : rel->rd_options = palloc(len);
6308 0 : if (fread(rel->rd_options, 1, len, fp) != len)
6309 0 : goto read_failed;
6310 0 : if (len != VARSIZE(rel->rd_options))
6311 0 : goto read_failed; /* sanity check */
6312 : }
6313 : else
6314 : {
6315 2540870 : rel->rd_options = NULL;
6316 : }
6317 :
6318 : /* mark not-null status */
6319 2540870 : if (has_not_null)
6320 : {
6321 948408 : TupleConstr *constr = palloc0_object(TupleConstr);
6322 :
6323 948408 : constr->has_not_null = true;
6324 948408 : rel->rd_att->constr = constr;
6325 : }
6326 :
6327 : /*
6328 : * If it's an index, there's more to do. Note we explicitly ignore
6329 : * partitioned indexes here.
6330 : */
6331 2540870 : if (rel->rd_rel->relkind == RELKIND_INDEX)
6332 : {
6333 : MemoryContext indexcxt;
6334 : Oid *opfamily;
6335 : Oid *opcintype;
6336 : RegProcedure *support;
6337 : int nsupport;
6338 : int16 *indoption;
6339 : Oid *indcollation;
6340 :
6341 : /* Count nailed indexes to ensure we have 'em all */
6342 1592462 : if (rel->rd_isnailed)
6343 223729 : nailed_indexes++;
6344 :
6345 : /* read the pg_index tuple */
6346 1592462 : if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6347 0 : goto read_failed;
6348 :
6349 1592462 : rel->rd_indextuple = (HeapTuple) palloc(len);
6350 1592462 : if (fread(rel->rd_indextuple, 1, len, fp) != len)
6351 0 : goto read_failed;
6352 :
6353 : /* Fix up internal pointers in the tuple -- see heap_copytuple */
6354 1592462 : rel->rd_indextuple->t_data = (HeapTupleHeader) ((char *) rel->rd_indextuple + HEAPTUPLESIZE);
6355 1592462 : rel->rd_index = (Form_pg_index) GETSTRUCT(rel->rd_indextuple);
6356 :
6357 : /*
6358 : * prepare index info context --- parameters should match
6359 : * RelationInitIndexAccessInfo
6360 : */
6361 1592462 : indexcxt = AllocSetContextCreate(CacheMemoryContext,
6362 : "index info",
6363 : ALLOCSET_SMALL_SIZES);
6364 1592462 : rel->rd_indexcxt = indexcxt;
6365 1592462 : MemoryContextCopyAndSetIdentifier(indexcxt,
6366 : RelationGetRelationName(rel));
6367 :
6368 : /*
6369 : * Now we can fetch the index AM's API struct. (We can't store
6370 : * that in the init file, since it contains function pointers that
6371 : * might vary across server executions. Fortunately, it should be
6372 : * safe to call the amhandler even while bootstrapping indexes.)
6373 : */
6374 1592462 : InitIndexAmRoutine(rel);
6375 :
6376 : /* read the vector of opfamily OIDs */
6377 1592462 : if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6378 0 : goto read_failed;
6379 :
6380 1592462 : opfamily = (Oid *) MemoryContextAlloc(indexcxt, len);
6381 1592462 : if (fread(opfamily, 1, len, fp) != len)
6382 0 : goto read_failed;
6383 :
6384 1592462 : rel->rd_opfamily = opfamily;
6385 :
6386 : /* read the vector of opcintype OIDs */
6387 1592462 : if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6388 0 : goto read_failed;
6389 :
6390 1592462 : opcintype = (Oid *) MemoryContextAlloc(indexcxt, len);
6391 1592462 : if (fread(opcintype, 1, len, fp) != len)
6392 0 : goto read_failed;
6393 :
6394 1592462 : rel->rd_opcintype = opcintype;
6395 :
6396 : /* read the vector of support procedure OIDs */
6397 1592462 : if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6398 0 : goto read_failed;
6399 1592462 : support = (RegProcedure *) MemoryContextAlloc(indexcxt, len);
6400 1592462 : if (fread(support, 1, len, fp) != len)
6401 0 : goto read_failed;
6402 :
6403 1592462 : rel->rd_support = support;
6404 :
6405 : /* read the vector of collation OIDs */
6406 1592462 : if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6407 0 : goto read_failed;
6408 :
6409 1592462 : indcollation = (Oid *) MemoryContextAlloc(indexcxt, len);
6410 1592462 : if (fread(indcollation, 1, len, fp) != len)
6411 0 : goto read_failed;
6412 :
6413 1592462 : rel->rd_indcollation = indcollation;
6414 :
6415 : /* read the vector of indoption values */
6416 1592462 : if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6417 0 : goto read_failed;
6418 :
6419 1592462 : indoption = (int16 *) MemoryContextAlloc(indexcxt, len);
6420 1592462 : if (fread(indoption, 1, len, fp) != len)
6421 0 : goto read_failed;
6422 :
6423 1592462 : rel->rd_indoption = indoption;
6424 :
6425 : /* read the vector of opcoptions values */
6426 1592462 : rel->rd_opcoptions = (bytea **)
6427 1592462 : MemoryContextAllocZero(indexcxt, sizeof(*rel->rd_opcoptions) * relform->relnatts);
6428 :
6429 4199724 : for (i = 0; i < relform->relnatts; i++)
6430 : {
6431 2607262 : if (fread(&len, 1, sizeof(len), fp) != sizeof(len))
6432 0 : goto read_failed;
6433 :
6434 2607262 : if (len > 0)
6435 : {
6436 0 : rel->rd_opcoptions[i] = (bytea *) MemoryContextAlloc(indexcxt, len);
6437 0 : if (fread(rel->rd_opcoptions[i], 1, len, fp) != len)
6438 0 : goto read_failed;
6439 : }
6440 : }
6441 :
6442 : /* set up zeroed fmgr-info vector */
6443 1592462 : nsupport = relform->relnatts * rel->rd_indam->amsupport;
6444 1592462 : rel->rd_supportinfo = (FmgrInfo *)
6445 1592462 : MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
6446 : }
6447 : else
6448 : {
6449 : /* Count nailed rels to ensure we have 'em all */
6450 948408 : if (rel->rd_isnailed)
6451 155617 : nailed_rels++;
6452 :
6453 : /* Load table AM data */
6454 948408 : if (RELKIND_HAS_TABLE_AM(rel->rd_rel->relkind) || rel->rd_rel->relkind == RELKIND_SEQUENCE)
6455 948408 : RelationInitTableAccessMethod(rel);
6456 :
6457 : Assert(rel->rd_index == NULL);
6458 : Assert(rel->rd_indextuple == NULL);
6459 : Assert(rel->rd_indexcxt == NULL);
6460 : Assert(rel->rd_indam == NULL);
6461 : Assert(rel->rd_opfamily == NULL);
6462 : Assert(rel->rd_opcintype == NULL);
6463 : Assert(rel->rd_support == NULL);
6464 : Assert(rel->rd_supportinfo == NULL);
6465 : Assert(rel->rd_indoption == NULL);
6466 : Assert(rel->rd_indcollation == NULL);
6467 : Assert(rel->rd_opcoptions == NULL);
6468 : }
6469 :
6470 : /*
6471 : * Rules and triggers are not saved (mainly because the internal
6472 : * format is complex and subject to change). They must be rebuilt if
6473 : * needed by RelationCacheInitializePhase3. This is not expected to
6474 : * be a big performance hit since few system catalogs have such. Ditto
6475 : * for RLS policy data, partition info, index expressions, predicates,
6476 : * exclusion info, and FDW info.
6477 : */
6478 2540870 : rel->rd_rules = NULL;
6479 2540870 : rel->rd_rulescxt = NULL;
6480 2540870 : rel->trigdesc = NULL;
6481 2540870 : rel->rd_rsdesc = NULL;
6482 2540870 : rel->rd_partkey = NULL;
6483 2540870 : rel->rd_partkeycxt = NULL;
6484 2540870 : rel->rd_partdesc = NULL;
6485 2540870 : rel->rd_partdesc_nodetached = NULL;
6486 2540870 : rel->rd_partdesc_nodetached_xmin = InvalidTransactionId;
6487 2540870 : rel->rd_pdcxt = NULL;
6488 2540870 : rel->rd_pddcxt = NULL;
6489 2540870 : rel->rd_partcheck = NIL;
6490 2540870 : rel->rd_partcheckvalid = false;
6491 2540870 : rel->rd_partcheckcxt = NULL;
6492 2540870 : rel->rd_indexprs = NIL;
6493 2540870 : rel->rd_indpred = NIL;
6494 2540870 : rel->rd_exclops = NULL;
6495 2540870 : rel->rd_exclprocs = NULL;
6496 2540870 : rel->rd_exclstrats = NULL;
6497 2540870 : rel->rd_fdwroutine = NULL;
6498 :
6499 : /*
6500 : * Reset transient-state fields in the relcache entry
6501 : */
6502 2540870 : rel->rd_smgr = NULL;
6503 2540870 : if (rel->rd_isnailed)
6504 379346 : rel->rd_refcnt = 1;
6505 : else
6506 2161524 : rel->rd_refcnt = 0;
6507 2540870 : rel->rd_indexvalid = false;
6508 2540870 : rel->rd_indexlist = NIL;
6509 2540870 : rel->rd_pkindex = InvalidOid;
6510 2540870 : rel->rd_replidindex = InvalidOid;
6511 2540870 : rel->rd_attrsvalid = false;
6512 2540870 : rel->rd_keyattr = NULL;
6513 2540870 : rel->rd_pkattr = NULL;
6514 2540870 : rel->rd_idattr = NULL;
6515 2540870 : rel->rd_pubdesc = NULL;
6516 2540870 : rel->rd_statvalid = false;
6517 2540870 : rel->rd_statlist = NIL;
6518 2540870 : rel->rd_fkeyvalid = false;
6519 2540870 : rel->rd_fkeylist = NIL;
6520 2540870 : rel->rd_createSubid = InvalidSubTransactionId;
6521 2540870 : rel->rd_newRelfilelocatorSubid = InvalidSubTransactionId;
6522 2540870 : rel->rd_firstRelfilelocatorSubid = InvalidSubTransactionId;
6523 2540870 : rel->rd_droppedSubid = InvalidSubTransactionId;
6524 2540870 : rel->rd_amcache = NULL;
6525 2540870 : rel->pgstat_info = NULL;
6526 :
6527 : /*
6528 : * Recompute lock and physical addressing info. This is needed in
6529 : * case the pg_internal.init file was copied from some other database
6530 : * by CREATE DATABASE.
6531 : */
6532 2540870 : RelationInitLockInfo(rel);
6533 2540870 : RelationInitPhysicalAddr(rel);
6534 : }
6535 :
6536 : /*
6537 : * We reached the end of the init file without apparent problem. Did we
6538 : * get the right number of nailed items? This is a useful crosscheck in
6539 : * case the set of critical rels or indexes changes. However, that should
6540 : * not happen in a normally-running system, so let's bleat if it does.
6541 : *
6542 : * For the shared init file, we're called before client authentication is
6543 : * done, which means that elog(WARNING) will go only to the postmaster
6544 : * log, where it's easily missed. To ensure that developers notice bad
6545 : * values of NUM_CRITICAL_SHARED_RELS/NUM_CRITICAL_SHARED_INDEXES, we put
6546 : * an Assert(false) there.
6547 : */
6548 34486 : if (shared)
6549 : {
6550 17673 : if (nailed_rels != NUM_CRITICAL_SHARED_RELS ||
6551 : nailed_indexes != NUM_CRITICAL_SHARED_INDEXES)
6552 : {
6553 0 : elog(WARNING, "found %d nailed shared rels and %d nailed shared indexes in init file, but expected %d and %d respectively",
6554 : nailed_rels, nailed_indexes,
6555 : NUM_CRITICAL_SHARED_RELS, NUM_CRITICAL_SHARED_INDEXES);
6556 : /* Make sure we get developers' attention about this */
6557 : Assert(false);
6558 : /* In production builds, recover by bootstrapping the relcache */
6559 0 : goto read_failed;
6560 : }
6561 : }
6562 : else
6563 : {
6564 16813 : if (nailed_rels != NUM_CRITICAL_LOCAL_RELS ||
6565 : nailed_indexes != NUM_CRITICAL_LOCAL_INDEXES)
6566 : {
6567 0 : elog(WARNING, "found %d nailed rels and %d nailed indexes in init file, but expected %d and %d respectively",
6568 : nailed_rels, nailed_indexes,
6569 : NUM_CRITICAL_LOCAL_RELS, NUM_CRITICAL_LOCAL_INDEXES);
6570 : /* We don't need an Assert() in this case */
6571 0 : goto read_failed;
6572 : }
6573 : }
6574 :
6575 : /*
6576 : * OK, all appears well.
6577 : *
6578 : * Now insert all the new relcache entries into the cache.
6579 : */
6580 2575356 : for (relno = 0; relno < num_rels; relno++)
6581 : {
6582 2540870 : RelationCacheInsert(rels[relno], false);
6583 : }
6584 :
6585 34486 : pfree(rels);
6586 34486 : FreeFile(fp);
6587 :
6588 34486 : if (shared)
6589 17673 : criticalSharedRelcachesBuilt = true;
6590 : else
6591 16813 : criticalRelcachesBuilt = true;
6592 34486 : return true;
6593 :
6594 : /*
6595 : * init file is broken, so do it the hard way. We don't bother trying to
6596 : * free the clutter we just allocated; it's not in the relcache so it
6597 : * won't hurt.
6598 : */
6599 0 : read_failed:
6600 0 : pfree(rels);
6601 0 : FreeFile(fp);
6602 :
6603 0 : return false;
6604 : }
6605 :
6606 : /*
6607 : * Write out a new initialization file with the current contents
6608 : * of the relcache (either shared rels or local rels, as indicated).
6609 : */
6610 : static void
6611 4102 : write_relcache_init_file(bool shared)
6612 : {
6613 : FILE *fp;
6614 : char tempfilename[MAXPGPATH];
6615 : char finalfilename[MAXPGPATH];
6616 : int magic;
6617 : HASH_SEQ_STATUS status;
6618 : RelIdCacheEnt *idhentry;
6619 : int i;
6620 :
6621 : /*
6622 : * If we have already received any relcache inval events, there's no
6623 : * chance of succeeding so we may as well skip the whole thing.
6624 : */
6625 4102 : if (relcacheInvalsReceived != 0L)
6626 44 : return;
6627 :
6628 : /*
6629 : * We must write a temporary file and rename it into place. Otherwise,
6630 : * another backend starting at about the same time might crash trying to
6631 : * read the partially-complete file.
6632 : */
6633 4058 : if (shared)
6634 : {
6635 2030 : snprintf(tempfilename, sizeof(tempfilename), "global/%s.%d",
6636 : RELCACHE_INIT_FILENAME, MyProcPid);
6637 2030 : snprintf(finalfilename, sizeof(finalfilename), "global/%s",
6638 : RELCACHE_INIT_FILENAME);
6639 : }
6640 : else
6641 : {
6642 2028 : snprintf(tempfilename, sizeof(tempfilename), "%s/%s.%d",
6643 : DatabasePath, RELCACHE_INIT_FILENAME, MyProcPid);
6644 2028 : snprintf(finalfilename, sizeof(finalfilename), "%s/%s",
6645 : DatabasePath, RELCACHE_INIT_FILENAME);
6646 : }
6647 :
6648 4058 : unlink(tempfilename); /* in case it exists w/wrong permissions */
6649 :
6650 4058 : fp = AllocateFile(tempfilename, PG_BINARY_W);
6651 4058 : if (fp == NULL)
6652 : {
6653 : /*
6654 : * We used to consider this a fatal error, but we might as well
6655 : * continue with backend startup ...
6656 : */
6657 0 : ereport(WARNING,
6658 : (errcode_for_file_access(),
6659 : errmsg("could not create relation-cache initialization file \"%s\": %m",
6660 : tempfilename),
6661 : errdetail("Continuing anyway, but there's something wrong.")));
6662 0 : return;
6663 : }
6664 :
6665 : /*
6666 : * Write a magic number to serve as a file version identifier. We can
6667 : * change the magic number whenever the relcache layout changes.
6668 : */
6669 4058 : magic = RELCACHE_INIT_FILEMAGIC;
6670 4058 : if (fwrite(&magic, 1, sizeof(magic), fp) != sizeof(magic))
6671 0 : ereport(FATAL,
6672 : errcode_for_file_access(),
6673 : errmsg_internal("could not write init file: %m"));
6674 :
6675 : /*
6676 : * Write all the appropriate reldescs (in no particular order).
6677 : */
6678 4058 : hash_seq_init(&status, RelationIdCache);
6679 :
6680 612758 : while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
6681 : {
6682 608700 : Relation rel = idhentry->reldesc;
6683 608700 : Form_pg_class relform = rel->rd_rel;
6684 :
6685 : /* ignore if not correct group */
6686 608700 : if (relform->relisshared != shared)
6687 304456 : continue;
6688 :
6689 : /*
6690 : * Ignore if not supposed to be in init file. We can allow any shared
6691 : * relation that's been loaded so far to be in the shared init file,
6692 : * but unshared relations must be ones that should be in the local
6693 : * file per RelationIdIsInInitFile. (Note: if you want to change the
6694 : * criterion for rels to be kept in the init file, see also inval.c.
6695 : * The reason for filtering here is to be sure that we don't put
6696 : * anything into the local init file for which a relcache inval would
6697 : * not cause invalidation of that init file.)
6698 : */
6699 304244 : if (!shared && !RelationIdIsInInitFile(RelationGetRelid(rel)))
6700 : {
6701 : /* Nailed rels had better get stored. */
6702 : Assert(!rel->rd_isnailed);
6703 0 : continue;
6704 : }
6705 :
6706 : /* first write the relcache entry proper */
6707 304244 : write_item(rel, sizeof(RelationData), fp);
6708 :
6709 : /* next write the relation tuple form */
6710 304244 : write_item(relform, CLASS_TUPLE_SIZE, fp);
6711 :
6712 : /* next, do all the attribute tuple form data entries */
6713 1770678 : for (i = 0; i < relform->relnatts; i++)
6714 : {
6715 1466434 : write_item(TupleDescAttr(rel->rd_att, i),
6716 : ATTRIBUTE_FIXED_PART_SIZE, fp);
6717 : }
6718 :
6719 : /* next, do the access method specific field */
6720 304244 : write_item(rel->rd_options,
6721 304244 : (rel->rd_options ? VARSIZE(rel->rd_options) : 0),
6722 : fp);
6723 :
6724 : /*
6725 : * If it's an index, there's more to do. Note we explicitly ignore
6726 : * partitioned indexes here.
6727 : */
6728 304244 : if (rel->rd_rel->relkind == RELKIND_INDEX)
6729 : {
6730 : /* write the pg_index tuple */
6731 : /* we assume this was created by heap_copytuple! */
6732 190660 : write_item(rel->rd_indextuple,
6733 190660 : HEAPTUPLESIZE + rel->rd_indextuple->t_len,
6734 : fp);
6735 :
6736 : /* write the vector of opfamily OIDs */
6737 190660 : write_item(rel->rd_opfamily,
6738 190660 : relform->relnatts * sizeof(Oid),
6739 : fp);
6740 :
6741 : /* write the vector of opcintype OIDs */
6742 190660 : write_item(rel->rd_opcintype,
6743 190660 : relform->relnatts * sizeof(Oid),
6744 : fp);
6745 :
6746 : /* write the vector of support procedure OIDs */
6747 190660 : write_item(rel->rd_support,
6748 190660 : relform->relnatts * (rel->rd_indam->amsupport * sizeof(RegProcedure)),
6749 : fp);
6750 :
6751 : /* write the vector of collation OIDs */
6752 190660 : write_item(rel->rd_indcollation,
6753 190660 : relform->relnatts * sizeof(Oid),
6754 : fp);
6755 :
6756 : /* write the vector of indoption values */
6757 190660 : write_item(rel->rd_indoption,
6758 190660 : relform->relnatts * sizeof(int16),
6759 : fp);
6760 :
6761 : Assert(rel->rd_opcoptions);
6762 :
6763 : /* write the vector of opcoptions values */
6764 503014 : for (i = 0; i < relform->relnatts; i++)
6765 : {
6766 312354 : bytea *opt = rel->rd_opcoptions[i];
6767 :
6768 312354 : write_item(opt, opt ? VARSIZE(opt) : 0, fp);
6769 : }
6770 : }
6771 : }
6772 :
6773 4058 : if (FreeFile(fp))
6774 0 : ereport(FATAL,
6775 : errcode_for_file_access(),
6776 : errmsg_internal("could not write init file: %m"));
6777 :
6778 : /*
6779 : * Now we have to check whether the data we've so painstakingly
6780 : * accumulated is already obsolete due to someone else's just-committed
6781 : * catalog changes. If so, we just delete the temp file and leave it to
6782 : * the next backend to try again. (Our own relcache entries will be
6783 : * updated by SI message processing, but we can't be sure whether what we
6784 : * wrote out was up-to-date.)
6785 : *
6786 : * This mustn't run concurrently with the code that unlinks an init file
6787 : * and sends SI messages, so grab a serialization lock for the duration.
6788 : */
6789 4058 : LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6790 :
6791 : /* Make sure we have seen all incoming SI messages */
6792 4058 : AcceptInvalidationMessages();
6793 :
6794 : /*
6795 : * If we have received any SI relcache invals since backend start, assume
6796 : * we may have written out-of-date data.
6797 : */
6798 4058 : if (relcacheInvalsReceived == 0L)
6799 : {
6800 : /*
6801 : * OK, rename the temp file to its final name, deleting any
6802 : * previously-existing init file.
6803 : *
6804 : * Note: a failure here is possible under Cygwin, if some other
6805 : * backend is holding open an unlinked-but-not-yet-gone init file. So
6806 : * treat this as a noncritical failure; just remove the useless temp
6807 : * file on failure.
6808 : */
6809 4056 : if (rename(tempfilename, finalfilename) < 0)
6810 0 : unlink(tempfilename);
6811 : }
6812 : else
6813 : {
6814 : /* Delete the already-obsolete temp file */
6815 2 : unlink(tempfilename);
6816 : }
6817 :
6818 4058 : LWLockRelease(RelCacheInitLock);
6819 : }
6820 :
6821 : /* write a chunk of data preceded by its length */
6822 : static void
6823 3835480 : write_item(const void *data, Size len, FILE *fp)
6824 : {
6825 3835480 : if (fwrite(&len, 1, sizeof(len), fp) != sizeof(len))
6826 0 : ereport(FATAL,
6827 : errcode_for_file_access(),
6828 : errmsg_internal("could not write init file: %m"));
6829 3835480 : if (len > 0 && fwrite(data, 1, len, fp) != len)
6830 0 : ereport(FATAL,
6831 : errcode_for_file_access(),
6832 : errmsg_internal("could not write init file: %m"));
6833 3835480 : }
6834 :
6835 : /*
6836 : * Determine whether a given relation (identified by OID) is one of the ones
6837 : * we should store in a relcache init file.
6838 : *
6839 : * We must cache all nailed rels, and for efficiency we should cache every rel
6840 : * that supports a syscache. The former set is almost but not quite a subset
6841 : * of the latter. The special cases are relations where
6842 : * RelationCacheInitializePhase2/3 chooses to nail for efficiency reasons, but
6843 : * which do not support any syscache.
6844 : */
6845 : bool
6846 1745740 : RelationIdIsInInitFile(Oid relationId)
6847 : {
6848 1745740 : if (relationId == SharedSecLabelRelationId ||
6849 1741459 : relationId == TriggerRelidNameIndexId ||
6850 1741288 : relationId == DatabaseNameIndexId ||
6851 : relationId == SharedSecLabelObjectIndexId)
6852 : {
6853 : /*
6854 : * If this Assert fails, we don't need the applicable special case
6855 : * anymore.
6856 : */
6857 : Assert(!RelationSupportsSysCache(relationId));
6858 4632 : return true;
6859 : }
6860 1741108 : return RelationSupportsSysCache(relationId);
6861 : }
6862 :
6863 : /*
6864 : * Invalidate (remove) the init file during commit of a transaction that
6865 : * changed one or more of the relation cache entries that are kept in the
6866 : * local init file.
6867 : *
6868 : * To be safe against concurrent inspection or rewriting of the init file,
6869 : * we must take RelCacheInitLock, then remove the old init file, then send
6870 : * the SI messages that include relcache inval for such relations, and then
6871 : * release RelCacheInitLock. This serializes the whole affair against
6872 : * write_relcache_init_file, so that we can be sure that any other process
6873 : * that's concurrently trying to create a new init file won't move an
6874 : * already-stale version into place after we unlink. Also, because we unlink
6875 : * before sending the SI messages, a backend that's currently starting cannot
6876 : * read the now-obsolete init file and then miss the SI messages that will
6877 : * force it to update its relcache entries. (This works because the backend
6878 : * startup sequence gets into the sinval array before trying to load the init
6879 : * file.)
6880 : *
6881 : * We take the lock and do the unlink in RelationCacheInitFilePreInvalidate,
6882 : * then release the lock in RelationCacheInitFilePostInvalidate. Caller must
6883 : * send any pending SI messages between those calls.
6884 : */
6885 : void
6886 43732 : RelationCacheInitFilePreInvalidate(void)
6887 : {
6888 : char localinitfname[MAXPGPATH];
6889 : char sharedinitfname[MAXPGPATH];
6890 :
6891 43732 : if (DatabasePath)
6892 43732 : snprintf(localinitfname, sizeof(localinitfname), "%s/%s",
6893 : DatabasePath, RELCACHE_INIT_FILENAME);
6894 43732 : snprintf(sharedinitfname, sizeof(sharedinitfname), "global/%s",
6895 : RELCACHE_INIT_FILENAME);
6896 :
6897 43732 : LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);
6898 :
6899 : /*
6900 : * The files might not be there if no backend has been started since the
6901 : * last removal. But complain about failures other than ENOENT with
6902 : * ERROR. Fortunately, it's not too late to abort the transaction if we
6903 : * can't get rid of the would-be-obsolete init file.
6904 : */
6905 43732 : if (DatabasePath)
6906 43732 : unlink_initfile(localinitfname, ERROR);
6907 43732 : unlink_initfile(sharedinitfname, ERROR);
6908 43732 : }
6909 :
6910 : void
6911 43732 : RelationCacheInitFilePostInvalidate(void)
6912 : {
6913 43732 : LWLockRelease(RelCacheInitLock);
6914 43732 : }
6915 :
6916 : /*
6917 : * Remove the init files during postmaster startup.
6918 : *
6919 : * We used to keep the init files across restarts, but that is unsafe in PITR
6920 : * scenarios, and even in simple crash-recovery cases there are windows for
6921 : * the init files to become out-of-sync with the database. So now we just
6922 : * remove them during startup and expect the first backend launch to rebuild
6923 : * them. Of course, this has to happen in each database of the cluster.
6924 : */
6925 : void
6926 1089 : RelationCacheInitFileRemove(void)
6927 : {
6928 1089 : const char *tblspcdir = PG_TBLSPC_DIR;
6929 : DIR *dir;
6930 : struct dirent *de;
6931 : char path[MAXPGPATH + sizeof(PG_TBLSPC_DIR) + sizeof(TABLESPACE_VERSION_DIRECTORY)];
6932 :
6933 1089 : snprintf(path, sizeof(path), "global/%s",
6934 : RELCACHE_INIT_FILENAME);
6935 1089 : unlink_initfile(path, LOG);
6936 :
6937 : /* Scan everything in the default tablespace */
6938 1089 : RelationCacheInitFileRemoveInDir("base");
6939 :
6940 : /* Scan the tablespace link directory to find non-default tablespaces */
6941 1089 : dir = AllocateDir(tblspcdir);
6942 :
6943 4417 : while ((de = ReadDirExtended(dir, tblspcdir, LOG)) != NULL)
6944 : {
6945 2239 : if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6946 : {
6947 : /* Scan the tablespace dir for per-database dirs */
6948 61 : snprintf(path, sizeof(path), "%s/%s/%s",
6949 61 : tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
6950 61 : RelationCacheInitFileRemoveInDir(path);
6951 : }
6952 : }
6953 :
6954 1089 : FreeDir(dir);
6955 1089 : }
6956 :
6957 : /* Process one per-tablespace directory for RelationCacheInitFileRemove */
6958 : static void
6959 1150 : RelationCacheInitFileRemoveInDir(const char *tblspcpath)
6960 : {
6961 : DIR *dir;
6962 : struct dirent *de;
6963 : char initfilename[MAXPGPATH * 2];
6964 :
6965 : /* Scan the tablespace directory to find per-database directories */
6966 1150 : dir = AllocateDir(tblspcpath);
6967 :
6968 8144 : while ((de = ReadDirExtended(dir, tblspcpath, LOG)) != NULL)
6969 : {
6970 5844 : if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
6971 : {
6972 : /* Try to remove the init file in each database */
6973 3464 : snprintf(initfilename, sizeof(initfilename), "%s/%s/%s",
6974 3464 : tblspcpath, de->d_name, RELCACHE_INIT_FILENAME);
6975 3464 : unlink_initfile(initfilename, LOG);
6976 : }
6977 : }
6978 :
6979 1150 : FreeDir(dir);
6980 1150 : }
6981 :
6982 : static void
6983 92017 : unlink_initfile(const char *initfilename, int elevel)
6984 : {
6985 92017 : if (unlink(initfilename) < 0)
6986 : {
6987 : /* It might not be there, but log any error other than ENOENT */
6988 90149 : if (errno != ENOENT)
6989 0 : ereport(elevel,
6990 : (errcode_for_file_access(),
6991 : errmsg("could not remove cache file \"%s\": %m",
6992 : initfilename)));
6993 : }
6994 92017 : }
6995 :
6996 : /*
6997 : * ResourceOwner callbacks
6998 : */
6999 : static char *
7000 5 : ResOwnerPrintRelCache(Datum res)
7001 : {
7002 5 : Relation rel = (Relation) DatumGetPointer(res);
7003 :
7004 5 : return psprintf("relation \"%s\"", RelationGetRelationName(rel));
7005 : }
7006 :
7007 : static void
7008 32337 : ResOwnerReleaseRelation(Datum res)
7009 : {
7010 32337 : Relation rel = (Relation) DatumGetPointer(res);
7011 :
7012 : /*
7013 : * This reference has already been removed from the resource owner, so
7014 : * just decrement reference count without calling
7015 : * ResourceOwnerForgetRelationRef.
7016 : */
7017 : Assert(rel->rd_refcnt > 0);
7018 32337 : rel->rd_refcnt -= 1;
7019 :
7020 32337 : RelationCloseCleanup((Relation) DatumGetPointer(res));
7021 32337 : }
|