LCOV - code coverage report
Current view: top level - src/backend/utils/cache - relcache.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 1661 1892 87.8 %
Date: 2017-09-29 13:40:31 Functions: 72 74 97.3 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.11