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