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