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