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