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