Header And Logo

PostgreSQL
| The world's most advanced open source database.

Typedefs | Functions | Variables

relcache.h File Reference

#include "access/tupdesc.h"
#include "nodes/bitmapset.h"
Include dependency graph for relcache.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Typedefs

typedef struct RelationDataRelation
typedef RelationRelationPtr

Functions

Relation RelationIdGetRelation (Oid relationId)
void RelationClose (Relation relation)
ListRelationGetIndexList (Relation relation)
Oid RelationGetOidIndex (Relation relation)
ListRelationGetIndexExpressions (Relation relation)
ListRelationGetIndexPredicate (Relation relation)
BitmapsetRelationGetIndexAttrBitmap (Relation relation, bool keyAttrs)
void RelationGetExclusionInfo (Relation indexRelation, Oid **operators, Oid **procs, uint16 **strategies)
void RelationSetIndexList (Relation relation, List *indexIds, Oid oidIndex)
void RelationInitIndexAccessInfo (Relation relation)
int errtable (Relation rel)
int errtablecol (Relation rel, int attnum)
int errtablecolname (Relation rel, const char *colname)
int errtableconstraint (Relation rel, const char *conname)
void RelationCacheInitialize (void)
void RelationCacheInitializePhase2 (void)
void RelationCacheInitializePhase3 (void)
Relation RelationBuildLocalRelation (const char *relname, Oid relnamespace, TupleDesc tupDesc, Oid relid, Oid relfilenode, Oid reltablespace, bool shared_relation, bool mapped_relation, char relpersistence, char relkind)
void RelationSetNewRelfilenode (Relation relation, TransactionId freezeXid, MultiXactId minmulti)
void RelationForgetRelation (Oid rid)
void RelationCacheInvalidateEntry (Oid relationId)
void RelationCacheInvalidate (void)
void RelationCloseSmgrByOid (Oid relationId)
void AtEOXact_RelationCache (bool isCommit)
void AtEOSubXact_RelationCache (bool isCommit, SubTransactionId mySubid, SubTransactionId parentSubid)
bool RelationIdIsInInitFile (Oid relationId)
void RelationCacheInitFilePreInvalidate (void)
void RelationCacheInitFilePostInvalidate (void)
void RelationCacheInitFileRemove (void)

Variables

bool criticalRelcachesBuilt
bool criticalSharedRelcachesBuilt

Typedef Documentation

typedef struct RelationData* Relation

Definition at line 21 of file relcache.h.

Definition at line 29 of file relcache.h.


Function Documentation

void AtEOSubXact_RelationCache ( bool  isCommit,
SubTransactionId  mySubid,
SubTransactionId  parentSubid 
)

Definition at line 2438 of file relcache.c.

References AtEOSubXact_cleanup(), eoxact_list, eoxact_list_len, eoxact_list_overflowed, hash_search(), hash_seq_init(), hash_seq_search(), i, NULL, and relidcacheent::reldesc.

Referenced by AbortSubTransaction(), and CommitSubTransaction().

{
    HASH_SEQ_STATUS status;
    RelIdCacheEnt *idhentry;
    int         i;

    /*
     * Unless the eoxact_list[] overflowed, we only need to examine the rels
     * listed in it.  Otherwise fall back on a hash_seq_search scan.  Same
     * logic as in AtEOXact_RelationCache.
     */
    if (eoxact_list_overflowed)
    {
        hash_seq_init(&status, RelationIdCache);
        while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
        {
            AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
                                mySubid, parentSubid);
        }
    }
    else
    {
        for (i = 0; i < eoxact_list_len; i++)
        {
            idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
                                                     (void *) &eoxact_list[i],
                                                     HASH_FIND,
                                                     NULL);
            if (idhentry != NULL)
                AtEOSubXact_cleanup(idhentry->reldesc, isCommit,
                                    mySubid, parentSubid);
        }
    }

    /* Don't reset the list; we still need more cleanup later */
}

void AtEOXact_RelationCache ( bool  isCommit  ) 

Definition at line 2314 of file relcache.c.

References AtEOXact_cleanup(), eoxact_list, eoxact_list_len, eoxact_list_overflowed, hash_search(), hash_seq_init(), hash_seq_search(), i, NULL, and relidcacheent::reldesc.

Referenced by AbortTransaction(), CommitTransaction(), and PrepareTransaction().

{
    HASH_SEQ_STATUS status;
    RelIdCacheEnt *idhentry;
    int         i;

    /*
     * Unless the eoxact_list[] overflowed, we only need to examine the rels
     * listed in it.  Otherwise fall back on a hash_seq_search scan.
     *
     * For simplicity, eoxact_list[] entries are not deleted till end of
     * top-level transaction, even though we could remove them at
     * subtransaction end in some cases, or remove relations from the list if
     * they are cleared for other reasons.  Therefore we should expect the
     * case that list entries are not found in the hashtable; if not, there's
     * nothing to do for them.
     */
    if (eoxact_list_overflowed)
    {
        hash_seq_init(&status, RelationIdCache);
        while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
        {
            AtEOXact_cleanup(idhentry->reldesc, isCommit);
        }
    }
    else
    {
        for (i = 0; i < eoxact_list_len; i++)
        {
            idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache,
                                                     (void *) &eoxact_list[i],
                                                     HASH_FIND,
                                                     NULL);
            if (idhentry != NULL)
                AtEOXact_cleanup(idhentry->reldesc, isCommit);
        }
    }

    /* Now we're out of the transaction and can clear the list */
    eoxact_list_len = 0;
    eoxact_list_overflowed = false;
}

int errtable ( Relation  rel  ) 
int errtablecol ( Relation  rel,
int  attnum 
)

Definition at line 4055 of file relcache.c.

References tupleDesc::attrs, errtablecolname(), get_relid_attribute_name(), NameStr, RelationGetDescr, and RelationGetRelid.

Referenced by AlterDomainNotNull(), ATRewriteTable(), ExecConstraints(), and validateDomainConstraint().

{
    TupleDesc   reldesc = RelationGetDescr(rel);
    const char *colname;

    /* Use reldesc if it's a user attribute, else consult the catalogs */
    if (attnum > 0 && attnum <= reldesc->natts)
        colname = NameStr(reldesc->attrs[attnum - 1]->attname);
    else
        colname = get_relid_attribute_name(RelationGetRelid(rel), attnum);

    return errtablecolname(rel, colname);
}

int errtablecolname ( Relation  rel,
const char *  colname 
)

Definition at line 4079 of file relcache.c.

References err_generic_string(), errtable(), and PG_DIAG_COLUMN_NAME.

Referenced by errtablecol().

{
    errtable(rel);
    err_generic_string(PG_DIAG_COLUMN_NAME, colname);

    return 0;           /* return value does not matter */
}

int errtableconstraint ( Relation  rel,
const char *  conname 
)
Relation RelationBuildLocalRelation ( const char *  relname,
Oid  relnamespace,
TupleDesc  tupDesc,
Oid  relid,
Oid  relfilenode,
Oid  reltablespace,
bool  shared_relation,
bool  mapped_relation,
char  relpersistence,
char  relkind 
)

Definition at line 2536 of file relcache.c.

References Assert, AssertArg, AttributeRelationId, tupleDesc::attrs, AuthIdRelationId, AuthMemRelationId, CacheMemoryContext, CLASS_TUPLE_SIZE, tupleDesc::constr, CreateCacheMemoryContext(), CreateTupleDescCopy(), DatabaseRelationId, elog, EOXactListAdd, ERROR, GetCurrentSubTransactionId(), tupleConstr::has_not_null, i, IsSharedRelation(), isTempOrToastNamespace(), MemoryContextSwitchTo(), MyBackendId, namestrcpy(), tupleDesc::natts, palloc0(), ProcedureRelationId, RelationData::rd_att, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_ispopulated, RelationData::rd_isvalid, RelationData::rd_newRelfilenodeSubid, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_smgr, RelationCacheInsert, RelationGetRelid, RelationIncrementReferenceCount(), RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationMapUpdateMap(), RelationRelationId, RELKIND_MATVIEW, RELPERSISTENCE_PERMANENT, RELPERSISTENCE_TEMP, RELPERSISTENCE_UNLOGGED, tupleDesc::tdhasoid, tupleDesc::tdrefcount, and TypeRelationId.

Referenced by heap_create().

{
    Relation    rel;
    MemoryContext oldcxt;
    int         natts = tupDesc->natts;
    int         i;
    bool        has_not_null;
    bool        nailit;

    AssertArg(natts >= 0);

    /*
     * check for creation of a rel that must be nailed in cache.
     *
     * XXX this list had better match the relations specially handled in
     * RelationCacheInitializePhase2/3.
     */
    switch (relid)
    {
        case DatabaseRelationId:
        case AuthIdRelationId:
        case AuthMemRelationId:
        case RelationRelationId:
        case AttributeRelationId:
        case ProcedureRelationId:
        case TypeRelationId:
            nailit = true;
            break;
        default:
            nailit = false;
            break;
    }

    /*
     * check that hardwired list of shared rels matches what's in the
     * bootstrap .bki file.  If you get a failure here during initdb, you
     * probably need to fix IsSharedRelation() to match whatever you've done
     * to the set of shared relations.
     */
    if (shared_relation != IsSharedRelation(relid))
        elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)",
             relname, relid);

    /* Shared relations had better be mapped, too */
    Assert(mapped_relation || !shared_relation);

    /*
     * switch to the cache context to create the relcache entry.
     */
    if (!CacheMemoryContext)
        CreateCacheMemoryContext();

    oldcxt = MemoryContextSwitchTo(CacheMemoryContext);

    /*
     * allocate a new relation descriptor and fill in basic state fields.
     */
    rel = (Relation) palloc0(sizeof(RelationData));

    /* make sure relation is marked as having no open file yet */
    rel->rd_smgr = NULL;

    /* mark it nailed if appropriate */
    rel->rd_isnailed = nailit;

    rel->rd_refcnt = nailit ? 1 : 0;

    /* it's being created in this transaction */
    rel->rd_createSubid = GetCurrentSubTransactionId();
    rel->rd_newRelfilenodeSubid = InvalidSubTransactionId;

    /*
     * create a new tuple descriptor from the one passed in.  We do this
     * partly to copy it into the cache context, and partly because the new
     * relation can't have any defaults or constraints yet; they have to be
     * added in later steps, because they require additions to multiple system
     * catalogs.  We can copy attnotnull constraints here, however.
     */
    rel->rd_att = CreateTupleDescCopy(tupDesc);
    rel->rd_att->tdrefcount = 1;    /* mark as refcounted */
    has_not_null = false;
    for (i = 0; i < natts; i++)
    {
        rel->rd_att->attrs[i]->attnotnull = tupDesc->attrs[i]->attnotnull;
        has_not_null |= tupDesc->attrs[i]->attnotnull;
    }

    if (has_not_null)
    {
        TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr));

        constr->has_not_null = true;
        rel->rd_att->constr = constr;
    }

    /*
     * initialize relation tuple form (caller may add/override data later)
     */
    rel->rd_rel = (Form_pg_class) palloc0(CLASS_TUPLE_SIZE);

    namestrcpy(&rel->rd_rel->relname, relname);
    rel->rd_rel->relnamespace = relnamespace;

    rel->rd_rel->relkind = relkind;
    rel->rd_rel->relhasoids = rel->rd_att->tdhasoid;
    rel->rd_rel->relnatts = natts;
    rel->rd_rel->reltype = InvalidOid;
    /* needed when bootstrapping: */
    rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID;

    /* set up persistence and relcache fields dependent on it */
    rel->rd_rel->relpersistence = relpersistence;
    switch (relpersistence)
    {
        case RELPERSISTENCE_UNLOGGED:
        case RELPERSISTENCE_PERMANENT:
            rel->rd_backend = InvalidBackendId;
            rel->rd_islocaltemp = false;
            break;
        case RELPERSISTENCE_TEMP:
            Assert(isTempOrToastNamespace(relnamespace));
            rel->rd_backend = MyBackendId;
            rel->rd_islocaltemp = true;
            break;
        default:
            elog(ERROR, "invalid relpersistence: %c", relpersistence);
            break;
    }

    /*
     * Insert relation physical and logical identifiers (OIDs) into the right
     * places.  For a mapped relation, we set relfilenode to zero and rely on
     * RelationInitPhysicalAddr to consult the map.
     */
    rel->rd_rel->relisshared = shared_relation;

    RelationGetRelid(rel) = relid;

    for (i = 0; i < natts; i++)
        rel->rd_att->attrs[i]->attrelid = relid;

    rel->rd_rel->reltablespace = reltablespace;

    if (mapped_relation)
    {
        rel->rd_rel->relfilenode = InvalidOid;
        /* Add it to the active mapping information */
        RelationMapUpdateMap(relid, relfilenode, shared_relation, true);
    }
    else
        rel->rd_rel->relfilenode = relfilenode;

    RelationInitLockInfo(rel);  /* see lmgr.c */

    RelationInitPhysicalAddr(rel);

    /* materialized view not initially scannable */
    if (relkind == RELKIND_MATVIEW)
        rel->rd_ispopulated = false;
    else
        rel->rd_ispopulated = true;

    /*
     * Okay to insert into the relcache hash tables.
     */
    RelationCacheInsert(rel);

    /*
     * Flag relation as needing eoxact cleanup (to clear rd_createSubid).
     * We can't do this before storing relid in it.
     */
    EOXactListAdd(rel);

    /*
     * done building relcache entry.
     */
    MemoryContextSwitchTo(oldcxt);

    /* It's fully valid */
    rel->rd_isvalid = true;

    /*
     * Caller expects us to pin the returned entry.
     */
    RelationIncrementReferenceCount(rel);

    return rel;
}

void RelationCacheInitFilePostInvalidate ( void   ) 
void RelationCacheInitFilePreInvalidate ( void   ) 

Definition at line 4754 of file relcache.c.

References DatabasePath, ereport, errcode_for_file_access(), errmsg(), ERROR, LW_EXCLUSIVE, LWLockAcquire(), RELCACHE_INIT_FILENAME, RelCacheInitLock, snprintf(), and unlink().

Referenced by AtEOXact_Inval(), FinishPreparedTransaction(), and ProcessCommittedInvalidationMessages().

{
    char        initfilename[MAXPGPATH];

    snprintf(initfilename, sizeof(initfilename), "%s/%s",
             DatabasePath, RELCACHE_INIT_FILENAME);

    LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE);

    if (unlink(initfilename) < 0)
    {
        /*
         * The file might not be there if no backend has been started since
         * the last removal.  But complain about failures other than ENOENT.
         * Fortunately, it's not too late to abort the transaction if we can't
         * get rid of the would-be-obsolete init file.
         */
        if (errno != ENOENT)
            ereport(ERROR,
                    (errcode_for_file_access(),
                     errmsg("could not remove cache file \"%s\": %m",
                            initfilename)));
    }
}

void RelationCacheInitFileRemove ( void   ) 

Definition at line 4795 of file relcache.c.

References AllocateDir(), dirent::d_name, elog, FreeDir(), LOG, NULL, ReadDir(), RelationCacheInitFileRemoveInDir(), RELCACHE_INIT_FILENAME, snprintf(), TABLESPACE_VERSION_DIRECTORY, and unlink_initfile().

Referenced by StartupXLOG().

{
    const char *tblspcdir = "pg_tblspc";
    DIR        *dir;
    struct dirent *de;
    char        path[MAXPGPATH];

    /*
     * We zap the shared cache file too.  In theory it can't get out of sync
     * enough to be a problem, but in data-corruption cases, who knows ...
     */
    snprintf(path, sizeof(path), "global/%s",
             RELCACHE_INIT_FILENAME);
    unlink_initfile(path);

    /* Scan everything in the default tablespace */
    RelationCacheInitFileRemoveInDir("base");

    /* Scan the tablespace link directory to find non-default tablespaces */
    dir = AllocateDir(tblspcdir);
    if (dir == NULL)
    {
        elog(LOG, "could not open tablespace link directory \"%s\": %m",
             tblspcdir);
        return;
    }

    while ((de = ReadDir(dir, tblspcdir)) != NULL)
    {
        if (strspn(de->d_name, "0123456789") == strlen(de->d_name))
        {
            /* Scan the tablespace dir for per-database dirs */
            snprintf(path, sizeof(path), "%s/%s/%s",
                     tblspcdir, de->d_name, TABLESPACE_VERSION_DIRECTORY);
            RelationCacheInitFileRemoveInDir(path);
        }
    }

    FreeDir(dir);
}

void RelationCacheInitialize ( void   ) 

Definition at line 2865 of file relcache.c.

References CacheMemoryContext, CreateCacheMemoryContext(), HASHCTL::entrysize, HASHCTL::hash, hash_create(), HASH_ELEM, HASH_FUNCTION, INITRELCACHESIZE, HASHCTL::keysize, MemSet, and RelationMapInitialize().

Referenced by InitPostgres().

{
    HASHCTL     ctl;

    /*
     * make sure cache memory context exists
     */
    if (!CacheMemoryContext)
        CreateCacheMemoryContext();

    /*
     * create hashtable that indexes the relcache
     */
    MemSet(&ctl, 0, sizeof(ctl));
    ctl.keysize = sizeof(Oid);
    ctl.entrysize = sizeof(RelIdCacheEnt);
    ctl.hash = oid_hash;
    RelationIdCache = hash_create("Relcache by OID", INITRELCACHESIZE,
                                  &ctl, HASH_ELEM | HASH_FUNCTION);

    /*
     * relation mapper needs to be initialized too
     */
    RelationMapInitialize();
}

void RelationCacheInitializePhase2 ( void   ) 

Definition at line 2903 of file relcache.c.

References AuthIdRelation_Rowtype_Id, AuthMemRelation_Rowtype_Id, CacheMemoryContext, DatabaseRelation_Rowtype_Id, Desc_pg_auth_members, Desc_pg_authid, Desc_pg_database, formrdesc(), IsBootstrapProcessingMode, load_relcache_init_file(), MemoryContextSwitchTo(), Natts_pg_auth_members, Natts_pg_authid, Natts_pg_database, and RelationMapInitializePhase2().

Referenced by InitPostgres().

{
    MemoryContext oldcxt;

    /*
     * relation mapper needs initialized too
     */
    RelationMapInitializePhase2();

    /*
     * In bootstrap mode, the shared catalogs aren't there yet anyway, so do
     * nothing.
     */
    if (IsBootstrapProcessingMode())
        return;

    /*
     * switch to cache memory context
     */
    oldcxt = MemoryContextSwitchTo(CacheMemoryContext);

    /*
     * Try to load the shared relcache cache file.  If unsuccessful, bootstrap
     * the cache with pre-made descriptors for the critical shared catalogs.
     */
    if (!load_relcache_init_file(true))
    {
        formrdesc("pg_database", DatabaseRelation_Rowtype_Id, true,
                  true, Natts_pg_database, Desc_pg_database);
        formrdesc("pg_authid", AuthIdRelation_Rowtype_Id, true,
                  true, Natts_pg_authid, Desc_pg_authid);
        formrdesc("pg_auth_members", AuthMemRelation_Rowtype_Id, true,
                  false, Natts_pg_auth_members, Desc_pg_auth_members);

#define NUM_CRITICAL_SHARED_RELS    3   /* fix if you change list above */
    }

    MemoryContextSwitchTo(oldcxt);
}

void RelationCacheInitializePhase3 ( void   ) 

Definition at line 2958 of file relcache.c.

References AccessMethodProcedureIndexId, AccessMethodProcedureRelationId, Assert, AttributeRelation_Rowtype_Id, AttributeRelationId, AttributeRelidNumIndexId, AuthIdOidIndexId, AuthIdRelationId, AuthIdRolnameIndexId, AuthMemMemRoleIndexId, AuthMemRelationId, CacheMemoryContext, CLASS_TUPLE_SIZE, ClassOidIndexId, criticalRelcachesBuilt, criticalSharedRelcachesBuilt, DatabaseNameIndexId, DatabaseOidIndexId, DatabaseRelationId, Desc_pg_attribute, Desc_pg_class, Desc_pg_proc, Desc_pg_type, elog, ERROR, FATAL, formrdesc(), GETSTRUCT, hash_seq_init(), hash_seq_search(), hash_seq_term(), HeapTupleIsValid, IndexRelationId, IndexRelidIndexId, InitCatalogCachePhase2(), InvalidOid, IsBootstrapProcessingMode, load_critical_index(), load_relcache_init_file(), MemoryContextSwitchTo(), Natts_pg_attribute, Natts_pg_class, Natts_pg_proc, Natts_pg_type, NULL, ObjectIdGetDatum, OpclassOidIndexId, OperatorClassRelationId, pfree(), ProcedureRelation_Rowtype_Id, RelationData::rd_att, RelationData::rd_options, RelationData::rd_rel, RelationData::rd_rules, RelationBuildRuleLock(), RelationBuildTriggers(), RelationDecrementReferenceCount(), RelationGetRelationName, RelationGetRelid, RelationIncrementReferenceCount(), RelationMapInitializePhase3(), RelationParseRelOptions(), RelationRelation_Rowtype_Id, RelationRelationId, relidcacheent::reldesc, ReleaseSysCache(), RELOID, RewriteRelationId, RewriteRelRulenameIndexId, SearchSysCache1, tupleDesc::tdhasoid, tupleDesc::tdtypeid, tupleDesc::tdtypmod, RelationData::trigdesc, TriggerRelationId, TriggerRelidNameIndexId, TypeRelation_Rowtype_Id, and write_relcache_init_file().

Referenced by InitPostgres().

{
    HASH_SEQ_STATUS status;
    RelIdCacheEnt *idhentry;
    MemoryContext oldcxt;
    bool        needNewCacheFile = !criticalSharedRelcachesBuilt;

    /*
     * relation mapper needs initialized too
     */
    RelationMapInitializePhase3();

    /*
     * switch to cache memory context
     */
    oldcxt = MemoryContextSwitchTo(CacheMemoryContext);

    /*
     * Try to load the local relcache cache file.  If unsuccessful, bootstrap
     * the cache with pre-made descriptors for the critical "nailed-in" system
     * catalogs.
     */
    if (IsBootstrapProcessingMode() ||
        !load_relcache_init_file(false))
    {
        needNewCacheFile = true;

        formrdesc("pg_class", RelationRelation_Rowtype_Id, false,
                  true, Natts_pg_class, Desc_pg_class);
        formrdesc("pg_attribute", AttributeRelation_Rowtype_Id, false,
                  false, Natts_pg_attribute, Desc_pg_attribute);
        formrdesc("pg_proc", ProcedureRelation_Rowtype_Id, false,
                  true, Natts_pg_proc, Desc_pg_proc);
        formrdesc("pg_type", TypeRelation_Rowtype_Id, false,
                  true, Natts_pg_type, Desc_pg_type);

#define NUM_CRITICAL_LOCAL_RELS 4       /* fix if you change list above */
    }

    MemoryContextSwitchTo(oldcxt);

    /* In bootstrap mode, the faked-up formrdesc info is all we'll have */
    if (IsBootstrapProcessingMode())
        return;

    /*
     * If we didn't get the critical system indexes loaded into relcache, do
     * so now.  These are critical because the catcache and/or opclass cache
     * depend on them for fetches done during relcache load.  Thus, we have an
     * infinite-recursion problem.  We can break the recursion by doing
     * heapscans instead of indexscans at certain key spots. To avoid hobbling
     * performance, we only want to do that until we have the critical indexes
     * loaded into relcache.  Thus, the flag criticalRelcachesBuilt is used to
     * decide whether to do heapscan or indexscan at the key spots, and we set
     * it true after we've loaded the critical indexes.
     *
     * The critical indexes are marked as "nailed in cache", partly to make it
     * easy for load_relcache_init_file to count them, but mainly because we
     * cannot flush and rebuild them once we've set criticalRelcachesBuilt to
     * true.  (NOTE: perhaps it would be possible to reload them by
     * temporarily setting criticalRelcachesBuilt to false again.  For now,
     * though, we just nail 'em in.)
     *
     * RewriteRelRulenameIndexId and TriggerRelidNameIndexId are not critical
     * in the same way as the others, because the critical catalogs don't
     * (currently) have any rules or triggers, and so these indexes can be
     * rebuilt without inducing recursion.  However they are used during
     * relcache load when a rel does have rules or triggers, so we choose to
     * nail them for performance reasons.
     */
    if (!criticalRelcachesBuilt)
    {
        load_critical_index(ClassOidIndexId,
                            RelationRelationId);
        load_critical_index(AttributeRelidNumIndexId,
                            AttributeRelationId);
        load_critical_index(IndexRelidIndexId,
                            IndexRelationId);
        load_critical_index(OpclassOidIndexId,
                            OperatorClassRelationId);
        load_critical_index(AccessMethodProcedureIndexId,
                            AccessMethodProcedureRelationId);
        load_critical_index(RewriteRelRulenameIndexId,
                            RewriteRelationId);
        load_critical_index(TriggerRelidNameIndexId,
                            TriggerRelationId);

#define NUM_CRITICAL_LOCAL_INDEXES  7   /* fix if you change list above */

        criticalRelcachesBuilt = true;
    }

    /*
     * Process critical shared indexes too.
     *
     * DatabaseNameIndexId isn't critical for relcache loading, but rather for
     * initial lookup of MyDatabaseId, without which we'll never find any
     * non-shared catalogs at all.  Autovacuum calls InitPostgres with a
     * database OID, so it instead depends on DatabaseOidIndexId.  We also
     * need to nail up some indexes on pg_authid and pg_auth_members for use
     * during client authentication.
     */
    if (!criticalSharedRelcachesBuilt)
    {
        load_critical_index(DatabaseNameIndexId,
                            DatabaseRelationId);
        load_critical_index(DatabaseOidIndexId,
                            DatabaseRelationId);
        load_critical_index(AuthIdRolnameIndexId,
                            AuthIdRelationId);
        load_critical_index(AuthIdOidIndexId,
                            AuthIdRelationId);
        load_critical_index(AuthMemMemRoleIndexId,
                            AuthMemRelationId);

#define NUM_CRITICAL_SHARED_INDEXES 5   /* fix if you change list above */

        criticalSharedRelcachesBuilt = true;
    }

    /*
     * Now, scan all the relcache entries and update anything that might be
     * wrong in the results from formrdesc or the relcache cache file. If we
     * faked up relcache entries using formrdesc, then read the real pg_class
     * rows and replace the fake entries with them. Also, if any of the
     * relcache entries have rules or triggers, load that info the hard way
     * since it isn't recorded in the cache file.
     *
     * Whenever we access the catalogs to read data, there is a possibility of
     * a shared-inval cache flush causing relcache entries to be removed.
     * Since hash_seq_search only guarantees to still work after the *current*
     * entry is removed, it's unsafe to continue the hashtable scan afterward.
     * We handle this by restarting the scan from scratch after each access.
     * This is theoretically O(N^2), but the number of entries that actually
     * need to be fixed is small enough that it doesn't matter.
     */
    hash_seq_init(&status, RelationIdCache);

    while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
    {
        Relation    relation = idhentry->reldesc;
        bool        restart = false;

        /*
         * Make sure *this* entry doesn't get flushed while we work with it.
         */
        RelationIncrementReferenceCount(relation);

        /*
         * If it's a faked-up entry, read the real pg_class tuple.
         */
        if (relation->rd_rel->relowner == InvalidOid)
        {
            HeapTuple   htup;
            Form_pg_class relp;

            htup = SearchSysCache1(RELOID,
                               ObjectIdGetDatum(RelationGetRelid(relation)));
            if (!HeapTupleIsValid(htup))
                elog(FATAL, "cache lookup failed for relation %u",
                     RelationGetRelid(relation));
            relp = (Form_pg_class) GETSTRUCT(htup);

            /*
             * Copy tuple to relation->rd_rel. (See notes in
             * AllocateRelationDesc())
             */
            memcpy((char *) relation->rd_rel, (char *) relp, CLASS_TUPLE_SIZE);

            /* Update rd_options while we have the tuple */
            if (relation->rd_options)
                pfree(relation->rd_options);
            RelationParseRelOptions(relation, htup);

            /*
             * Check the values in rd_att were set up correctly.  (We cannot
             * just copy them over now: formrdesc must have set up the rd_att
             * data correctly to start with, because it may already have been
             * copied into one or more catcache entries.)
             */
            Assert(relation->rd_att->tdtypeid == relp->reltype);
            Assert(relation->rd_att->tdtypmod == -1);
            Assert(relation->rd_att->tdhasoid == relp->relhasoids);

            ReleaseSysCache(htup);

            /* relowner had better be OK now, else we'll loop forever */
            if (relation->rd_rel->relowner == InvalidOid)
                elog(ERROR, "invalid relowner in pg_class entry for \"%s\"",
                     RelationGetRelationName(relation));

            restart = true;
        }

        /*
         * Fix data that isn't saved in relcache cache file.
         *
         * relhasrules or relhastriggers could possibly be wrong or out of
         * date.  If we don't actually find any rules or triggers, clear the
         * local copy of the flag so that we don't get into an infinite loop
         * here.  We don't make any attempt to fix the pg_class entry, though.
         */
        if (relation->rd_rel->relhasrules && relation->rd_rules == NULL)
        {
            RelationBuildRuleLock(relation);
            if (relation->rd_rules == NULL)
                relation->rd_rel->relhasrules = false;
            restart = true;
        }
        if (relation->rd_rel->relhastriggers && relation->trigdesc == NULL)
        {
            RelationBuildTriggers(relation);
            if (relation->trigdesc == NULL)
                relation->rd_rel->relhastriggers = false;
            restart = true;
        }

        /* Release hold on the relation */
        RelationDecrementReferenceCount(relation);

        /* Now, restart the hashtable scan if needed */
        if (restart)
        {
            hash_seq_term(&status);
            hash_seq_init(&status, RelationIdCache);
        }
    }

    /*
     * Lastly, write out new relcache cache files if needed.  We don't bother
     * to distinguish cases where only one of the two needs an update.
     */
    if (needNewCacheFile)
    {
        /*
         * Force all the catcaches to finish initializing and thereby open the
         * catalogs and indexes they use.  This will preload the relcache with
         * entries for all the most important system catalogs and indexes, so
         * that the init files will be most useful for future backends.
         */
        InitCatalogCachePhase2();

        /* reset initFileRelationIds list; we'll fill it during write */
        initFileRelationIds = NIL;

        /* now write the files */
        write_relcache_init_file(true);
        write_relcache_init_file(false);
    }
}

void RelationCacheInvalidate ( void   ) 

Definition at line 2182 of file relcache.c.

References Assert, ClassOidIndexId, hash_seq_init(), hash_seq_search(), InvalidSubTransactionId, lappend(), lcons(), lfirst, list_free(), NULL, RelationData::rd_createSubid, RelationData::rd_isnailed, RelationData::rd_newRelfilenodeSubid, RelationClearRelation(), RelationCloseSmgr, RelationGetRelid, RelationHasReferenceCountZero, RelationInitPhysicalAddr(), RelationIsMapped, RelationMapInvalidateAll(), RelationRelationId, relcacheInvalsReceived, relidcacheent::reldesc, and smgrcloseall().

Referenced by InvalidateSystemCaches().

{
    HASH_SEQ_STATUS status;
    RelIdCacheEnt *idhentry;
    Relation    relation;
    List       *rebuildFirstList = NIL;
    List       *rebuildList = NIL;
    ListCell   *l;

    /*
     * Reload relation mapping data before starting to reconstruct cache.
     */
    RelationMapInvalidateAll();

    /* Phase 1 */
    hash_seq_init(&status, RelationIdCache);

    while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL)
    {
        relation = idhentry->reldesc;

        /* Must close all smgr references to avoid leaving dangling ptrs */
        RelationCloseSmgr(relation);

        /*
         * Ignore new relations; no other backend will manipulate them before
         * we commit.  Likewise, before replacing a relation's relfilenode, we
         * shall have acquired AccessExclusiveLock and drained any applicable
         * pending invalidations.
         */
        if (relation->rd_createSubid != InvalidSubTransactionId ||
            relation->rd_newRelfilenodeSubid != InvalidSubTransactionId)
            continue;

        relcacheInvalsReceived++;

        if (RelationHasReferenceCountZero(relation))
        {
            /* Delete this entry immediately */
            Assert(!relation->rd_isnailed);
            RelationClearRelation(relation, false);
        }
        else
        {
            /*
             * If it's a mapped relation, immediately update its rd_node in
             * case its relfilenode changed.  We must do this during phase 1
             * in case the relation is consulted during rebuild of other
             * relcache entries in phase 2.  It's safe since consulting the
             * map doesn't involve any access to relcache entries.
             */
            if (RelationIsMapped(relation))
                RelationInitPhysicalAddr(relation);

            /*
             * Add this entry to list of stuff to rebuild in second pass.
             * pg_class goes to the front of rebuildFirstList while
             * pg_class_oid_index goes to the back of rebuildFirstList, so
             * they are done first and second respectively.  Other nailed
             * relations go to the front of rebuildList, so they'll be done
             * next in no particular order; and everything else goes to the
             * back of rebuildList.
             */
            if (RelationGetRelid(relation) == RelationRelationId)
                rebuildFirstList = lcons(relation, rebuildFirstList);
            else if (RelationGetRelid(relation) == ClassOidIndexId)
                rebuildFirstList = lappend(rebuildFirstList, relation);
            else if (relation->rd_isnailed)
                rebuildList = lcons(relation, rebuildList);
            else
                rebuildList = lappend(rebuildList, relation);
        }
    }

    /*
     * Now zap any remaining smgr cache entries.  This must happen before we
     * start to rebuild entries, since that may involve catalog fetches which
     * will re-open catalog files.
     */
    smgrcloseall();

    /* Phase 2: rebuild the items found to need rebuild in phase 1 */
    foreach(l, rebuildFirstList)
    {
        relation = (Relation) lfirst(l);
        RelationClearRelation(relation, true);
    }
    list_free(rebuildFirstList);
    foreach(l, rebuildList)
    {
        relation = (Relation) lfirst(l);
        RelationClearRelation(relation, true);
    }
    list_free(rebuildList);
}

void RelationCacheInvalidateEntry ( Oid  relationId  ) 
void RelationClose ( Relation  relation  ) 
void RelationCloseSmgrByOid ( Oid  relationId  ) 

Definition at line 2285 of file relcache.c.

References PointerIsValid, RelationCloseSmgr, and RelationIdCacheLookup.

Referenced by swap_relation_files().

{
    Relation    relation;

    RelationIdCacheLookup(relationId, relation);

    if (!PointerIsValid(relation))
        return;                 /* not in cache, nothing to do */

    RelationCloseSmgr(relation);
}

void RelationForgetRelation ( Oid  rid  ) 

Definition at line 2106 of file relcache.c.

References elog, ERROR, PointerIsValid, RelationClearRelation(), RelationHasReferenceCountZero, and RelationIdCacheLookup.

Referenced by heap_drop_with_catalog(), and index_drop().

{
    Relation    relation;

    RelationIdCacheLookup(rid, relation);

    if (!PointerIsValid(relation))
        return;                 /* not in cache, nothing to do */

    if (!RelationHasReferenceCountZero(relation))
        elog(ERROR, "relation %u is still open", rid);

    /* Unconditionally destroy the relcache entry */
    RelationClearRelation(relation, false);
}

void RelationGetExclusionInfo ( Relation  indexRelation,
Oid **  operators,
Oid **  procs,
uint16 **  strategies 
)

Definition at line 3910 of file relcache.c.

References AccessShareLock, Anum_pg_constraint_conexclop, Anum_pg_constraint_conrelid, ARR_DATA_PTR, ARR_DIMS, ARR_ELEMTYPE, ARR_HASNULL, ARR_NDIM, BTEqualStrategyNumber, CONSTRAINT_EXCLUSION, ConstraintRelationId, ConstraintRelidIndexId, DatumGetArrayTypeP, elog, ERROR, fastgetattr, get_op_opfamily_strategy(), get_opcode(), GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, i, InvalidStrategy, MemoryContextSwitchTo(), NULL, ObjectIdGetDatum, OIDOID, palloc(), RelationData::rd_att, RelationData::rd_exclops, RelationData::rd_exclprocs, RelationData::rd_exclstrats, RelationData::rd_index, RelationData::rd_indexcxt, RelationData::rd_opfamily, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), and val.

Referenced by BuildIndexInfo(), and CheckIndexCompatible().

{
    int         ncols = indexRelation->rd_rel->relnatts;
    Oid        *ops;
    Oid        *funcs;
    uint16     *strats;
    Relation    conrel;
    SysScanDesc conscan;
    ScanKeyData skey[1];
    HeapTuple   htup;
    bool        found;
    MemoryContext oldcxt;
    int         i;

    /* Allocate result space in caller context */
    *operators = ops = (Oid *) palloc(sizeof(Oid) * ncols);
    *procs = funcs = (Oid *) palloc(sizeof(Oid) * ncols);
    *strategies = strats = (uint16 *) palloc(sizeof(uint16) * ncols);

    /* Quick exit if we have the data cached already */
    if (indexRelation->rd_exclstrats != NULL)
    {
        memcpy(ops, indexRelation->rd_exclops, sizeof(Oid) * ncols);
        memcpy(funcs, indexRelation->rd_exclprocs, sizeof(Oid) * ncols);
        memcpy(strats, indexRelation->rd_exclstrats, sizeof(uint16) * ncols);
        return;
    }

    /*
     * Search pg_constraint for the constraint associated with the index. To
     * make this not too painfully slow, we use the index on conrelid; that
     * will hold the parent relation's OID not the index's own OID.
     */
    ScanKeyInit(&skey[0],
                Anum_pg_constraint_conrelid,
                BTEqualStrategyNumber, F_OIDEQ,
                ObjectIdGetDatum(indexRelation->rd_index->indrelid));

    conrel = heap_open(ConstraintRelationId, AccessShareLock);
    conscan = systable_beginscan(conrel, ConstraintRelidIndexId, true,
                                 SnapshotNow, 1, skey);
    found = false;

    while (HeapTupleIsValid(htup = systable_getnext(conscan)))
    {
        Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(htup);
        Datum       val;
        bool        isnull;
        ArrayType  *arr;
        int         nelem;

        /* We want the exclusion constraint owning the index */
        if (conform->contype != CONSTRAINT_EXCLUSION ||
            conform->conindid != RelationGetRelid(indexRelation))
            continue;

        /* There should be only one */
        if (found)
            elog(ERROR, "unexpected exclusion constraint record found for rel %s",
                 RelationGetRelationName(indexRelation));
        found = true;

        /* Extract the operator OIDS from conexclop */
        val = fastgetattr(htup,
                          Anum_pg_constraint_conexclop,
                          conrel->rd_att, &isnull);
        if (isnull)
            elog(ERROR, "null conexclop for rel %s",
                 RelationGetRelationName(indexRelation));

        arr = DatumGetArrayTypeP(val);  /* ensure not toasted */
        nelem = ARR_DIMS(arr)[0];
        if (ARR_NDIM(arr) != 1 ||
            nelem != ncols ||
            ARR_HASNULL(arr) ||
            ARR_ELEMTYPE(arr) != OIDOID)
            elog(ERROR, "conexclop is not a 1-D Oid array");

        memcpy(ops, ARR_DATA_PTR(arr), sizeof(Oid) * ncols);
    }

    systable_endscan(conscan);
    heap_close(conrel, AccessShareLock);

    if (!found)
        elog(ERROR, "exclusion constraint record missing for rel %s",
             RelationGetRelationName(indexRelation));

    /* We need the func OIDs and strategy numbers too */
    for (i = 0; i < ncols; i++)
    {
        funcs[i] = get_opcode(ops[i]);
        strats[i] = get_op_opfamily_strategy(ops[i],
                                             indexRelation->rd_opfamily[i]);
        /* shouldn't fail, since it was checked at index creation */
        if (strats[i] == InvalidStrategy)
            elog(ERROR, "could not find strategy for operator %u in family %u",
                 ops[i], indexRelation->rd_opfamily[i]);
    }

    /* Save a copy of the results in the relcache entry. */
    oldcxt = MemoryContextSwitchTo(indexRelation->rd_indexcxt);
    indexRelation->rd_exclops = (Oid *) palloc(sizeof(Oid) * ncols);
    indexRelation->rd_exclprocs = (Oid *) palloc(sizeof(Oid) * ncols);
    indexRelation->rd_exclstrats = (uint16 *) palloc(sizeof(uint16) * ncols);
    memcpy(indexRelation->rd_exclops, ops, sizeof(Oid) * ncols);
    memcpy(indexRelation->rd_exclprocs, funcs, sizeof(Oid) * ncols);
    memcpy(indexRelation->rd_exclstrats, strats, sizeof(uint16) * ncols);
    MemoryContextSwitchTo(oldcxt);
}

Bitmapset* RelationGetIndexAttrBitmap ( Relation  relation,
bool  keyAttrs 
)

Definition at line 3809 of file relcache.c.

References AccessShareLock, bms_add_member(), bms_copy(), BuildIndexInfo(), CacheMemoryContext, FirstLowInvalidHeapAttributeNumber, i, IndexInfo::ii_Expressions, IndexInfo::ii_KeyAttrNumbers, IndexInfo::ii_NumIndexAttrs, IndexInfo::ii_Predicate, IndexInfo::ii_Unique, index_close(), index_open(), lfirst_oid, list_free(), MemoryContextSwitchTo(), NIL, NULL, pull_varattnos(), RelationData::rd_indexattr, RelationData::rd_keyattr, RelationGetForm, and RelationGetIndexList().

Referenced by ExecBRUpdateTriggers(), heap_update(), and reindex_relation().

{
    Bitmapset  *indexattrs;
    Bitmapset  *uindexattrs;
    List       *indexoidlist;
    ListCell   *l;
    MemoryContext oldcxt;

    /* Quick exit if we already computed the result. */
    if (relation->rd_indexattr != NULL)
        return bms_copy(keyAttrs ? relation->rd_keyattr : relation->rd_indexattr);

    /* Fast path if definitely no indexes */
    if (!RelationGetForm(relation)->relhasindex)
        return NULL;

    /*
     * Get cached list of index OIDs
     */
    indexoidlist = RelationGetIndexList(relation);

    /* Fall out if no indexes (but relhasindex was set) */
    if (indexoidlist == NIL)
        return NULL;

    /*
     * For each index, add referenced attributes to indexattrs.
     *
     * Note: we consider all indexes returned by RelationGetIndexList, even if
     * they are not indisready or indisvalid.  This is important because an
     * index for which CREATE INDEX CONCURRENTLY has just started must be
     * included in HOT-safety decisions (see README.HOT).  If a DROP INDEX
     * CONCURRENTLY is far enough along that we should ignore the index, it
     * won't be returned at all by RelationGetIndexList.
     */
    indexattrs = NULL;
    uindexattrs = NULL;
    foreach(l, indexoidlist)
    {
        Oid         indexOid = lfirst_oid(l);
        Relation    indexDesc;
        IndexInfo  *indexInfo;
        int         i;
        bool        isKey;

        indexDesc = index_open(indexOid, AccessShareLock);

        /* Extract index key information from the index's pg_index row */
        indexInfo = BuildIndexInfo(indexDesc);

        /* Can this index be referenced by a foreign key? */
        isKey = indexInfo->ii_Unique &&
                indexInfo->ii_Expressions == NIL &&
                indexInfo->ii_Predicate == NIL;

        /* Collect simple attribute references */
        for (i = 0; i < indexInfo->ii_NumIndexAttrs; i++)
        {
            int         attrnum = indexInfo->ii_KeyAttrNumbers[i];

            if (attrnum != 0)
            {
                indexattrs = bms_add_member(indexattrs,
                               attrnum - FirstLowInvalidHeapAttributeNumber);
                if (isKey)
                    uindexattrs = bms_add_member(uindexattrs,
                                                 attrnum - FirstLowInvalidHeapAttributeNumber);
            }
        }

        /* Collect all attributes used in expressions, too */
        pull_varattnos((Node *) indexInfo->ii_Expressions, 1, &indexattrs);

        /* Collect all attributes in the index predicate, too */
        pull_varattnos((Node *) indexInfo->ii_Predicate, 1, &indexattrs);

        index_close(indexDesc, AccessShareLock);
    }

    list_free(indexoidlist);

    /* Now save a copy of the bitmap in the relcache entry. */
    oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
    relation->rd_indexattr = bms_copy(indexattrs);
    relation->rd_keyattr = bms_copy(uindexattrs);
    MemoryContextSwitchTo(oldcxt);

    /* We return our original working copy for caller to play with */
    return keyAttrs ? uindexattrs : indexattrs;
}

List* RelationGetIndexExpressions ( Relation  relation  ) 

Definition at line 3668 of file relcache.c.

References Anum_pg_index_indexprs, Assert, copyObject(), eval_const_expressions(), fix_opfuncids(), GetPgIndexDescriptor(), heap_attisnull(), heap_getattr, MemoryContextSwitchTo(), NULL, pfree(), RelationData::rd_indexcxt, RelationData::rd_indexprs, RelationData::rd_indextuple, stringToNode(), and TextDatumGetCString.

Referenced by BuildIndexInfo(), get_relation_info(), and transformIndexConstraint().

{
    List       *result;
    Datum       exprsDatum;
    bool        isnull;
    char       *exprsString;
    MemoryContext oldcxt;

    /* Quick exit if we already computed the result. */
    if (relation->rd_indexprs)
        return (List *) copyObject(relation->rd_indexprs);

    /* Quick exit if there is nothing to do. */
    if (relation->rd_indextuple == NULL ||
        heap_attisnull(relation->rd_indextuple, Anum_pg_index_indexprs))
        return NIL;

    /*
     * We build the tree we intend to return in the caller's context. After
     * successfully completing the work, we copy it into the relcache entry.
     * This avoids problems if we get some sort of error partway through.
     */
    exprsDatum = heap_getattr(relation->rd_indextuple,
                              Anum_pg_index_indexprs,
                              GetPgIndexDescriptor(),
                              &isnull);
    Assert(!isnull);
    exprsString = TextDatumGetCString(exprsDatum);
    result = (List *) stringToNode(exprsString);
    pfree(exprsString);

    /*
     * Run the expressions through eval_const_expressions. This is not just an
     * optimization, but is necessary, because the planner will be comparing
     * them to similarly-processed qual clauses, and may fail to detect valid
     * matches without this.  We don't bother with canonicalize_qual, however.
     */
    result = (List *) eval_const_expressions(NULL, (Node *) result);

    /* May as well fix opfuncids too */
    fix_opfuncids((Node *) result);

    /* Now save a copy of the completed tree in the relcache entry. */
    oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
    relation->rd_indexprs = (List *) copyObject(result);
    MemoryContextSwitchTo(oldcxt);

    return result;
}

List* RelationGetIndexList ( Relation  relation  ) 

Definition at line 3471 of file relcache.c.

References AccessShareLock, Anum_pg_index_indclass, Anum_pg_index_indpred, Anum_pg_index_indrelid, Assert, BTEqualStrategyNumber, CacheMemoryContext, DatumGetPointer, GetPgIndexDescriptor(), GETSTRUCT, heap_attisnull(), heap_close, heap_getattr, heap_open(), HeapTupleIsValid, IndexIndrelidIndexId, IndexIsLive, IndexIsValid, IndexRelationId, insert_ordered_oid(), list_copy(), MemoryContextSwitchTo(), ObjectIdAttributeNumber, ObjectIdGetDatum, OID_BTREE_OPS_OID, RelationData::rd_indexlist, RelationData::rd_indexvalid, RelationData::rd_oidindex, RelationGetRelid, ScanKeyInit(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), and oidvector::values.

Referenced by AlterIndexNamespaces(), ATExecChangeOwner(), ATExecDropNotNull(), calculate_indexes_size(), cluster(), ExecOpenIndices(), get_relation_info(), mark_index_clustered(), reindex_relation(), RelationGetIndexAttrBitmap(), RelationGetOidIndex(), relationHasPrimaryKey(), RelationTruncateIndexes(), transformFkeyCheckAttrs(), transformFkeyGetPrimaryKey(), transformTableLikeClause(), triggered_change_notification(), and vac_open_indexes().

{
    Relation    indrel;
    SysScanDesc indscan;
    ScanKeyData skey;
    HeapTuple   htup;
    List       *result;
    Oid         oidIndex;
    MemoryContext oldcxt;

    /* Quick exit if we already computed the list. */
    if (relation->rd_indexvalid != 0)
        return list_copy(relation->rd_indexlist);

    /*
     * We build the list we intend to return (in the caller's context) while
     * doing the scan.  After successfully completing the scan, we copy that
     * list into the relcache entry.  This avoids cache-context memory leakage
     * if we get some sort of error partway through.
     */
    result = NIL;
    oidIndex = InvalidOid;

    /* Prepare to scan pg_index for entries having indrelid = this rel. */
    ScanKeyInit(&skey,
                Anum_pg_index_indrelid,
                BTEqualStrategyNumber, F_OIDEQ,
                ObjectIdGetDatum(RelationGetRelid(relation)));

    indrel = heap_open(IndexRelationId, AccessShareLock);
    indscan = systable_beginscan(indrel, IndexIndrelidIndexId, true,
                                 SnapshotNow, 1, &skey);

    while (HeapTupleIsValid(htup = systable_getnext(indscan)))
    {
        Form_pg_index index = (Form_pg_index) GETSTRUCT(htup);
        Datum       indclassDatum;
        oidvector  *indclass;
        bool        isnull;

        /*
         * Ignore any indexes that are currently being dropped.  This will
         * prevent them from being searched, inserted into, or considered in
         * HOT-safety decisions.  It's unsafe to touch such an index at all
         * since its catalog entries could disappear at any instant.
         */
        if (!IndexIsLive(index))
            continue;

        /* Add index's OID to result list in the proper order */
        result = insert_ordered_oid(result, index->indexrelid);

        /*
         * indclass cannot be referenced directly through the C struct,
         * because it comes after the variable-width indkey field.  Must
         * extract the datum the hard way...
         */
        indclassDatum = heap_getattr(htup,
                                     Anum_pg_index_indclass,
                                     GetPgIndexDescriptor(),
                                     &isnull);
        Assert(!isnull);
        indclass = (oidvector *) DatumGetPointer(indclassDatum);

        /* Check to see if it is a unique, non-partial btree index on OID */
        if (IndexIsValid(index) &&
            index->indnatts == 1 &&
            index->indisunique && index->indimmediate &&
            index->indkey.values[0] == ObjectIdAttributeNumber &&
            indclass->values[0] == OID_BTREE_OPS_OID &&
            heap_attisnull(htup, Anum_pg_index_indpred))
            oidIndex = index->indexrelid;
    }

    systable_endscan(indscan);
    heap_close(indrel, AccessShareLock);

    /* Now save a copy of the completed list in the relcache entry. */
    oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
    relation->rd_indexlist = list_copy(result);
    relation->rd_oidindex = oidIndex;
    relation->rd_indexvalid = 1;
    MemoryContextSwitchTo(oldcxt);

    return result;
}

List* RelationGetIndexPredicate ( Relation  relation  ) 

Definition at line 3729 of file relcache.c.

References Anum_pg_index_indpred, Assert, canonicalize_qual(), copyObject(), eval_const_expressions(), fix_opfuncids(), GetPgIndexDescriptor(), heap_attisnull(), heap_getattr, make_ands_implicit(), MemoryContextSwitchTo(), NULL, pfree(), RelationData::rd_indexcxt, RelationData::rd_indextuple, RelationData::rd_indpred, stringToNode(), and TextDatumGetCString.

Referenced by BuildIndexInfo(), get_relation_info(), and transformIndexConstraint().

{
    List       *result;
    Datum       predDatum;
    bool        isnull;
    char       *predString;
    MemoryContext oldcxt;

    /* Quick exit if we already computed the result. */
    if (relation->rd_indpred)
        return (List *) copyObject(relation->rd_indpred);

    /* Quick exit if there is nothing to do. */
    if (relation->rd_indextuple == NULL ||
        heap_attisnull(relation->rd_indextuple, Anum_pg_index_indpred))
        return NIL;

    /*
     * We build the tree we intend to return in the caller's context. After
     * successfully completing the work, we copy it into the relcache entry.
     * This avoids problems if we get some sort of error partway through.
     */
    predDatum = heap_getattr(relation->rd_indextuple,
                             Anum_pg_index_indpred,
                             GetPgIndexDescriptor(),
                             &isnull);
    Assert(!isnull);
    predString = TextDatumGetCString(predDatum);
    result = (List *) stringToNode(predString);
    pfree(predString);

    /*
     * Run the expression through const-simplification and canonicalization.
     * This is not just an optimization, but is necessary, because the planner
     * will be comparing it to similarly-processed qual clauses, and may fail
     * to detect valid matches without this.  This must match the processing
     * done to qual clauses in preprocess_expression()!  (We can skip the
     * stuff involving subqueries, however, since we don't allow any in index
     * predicates.)
     */
    result = (List *) eval_const_expressions(NULL, (Node *) result);

    result = (List *) canonicalize_qual((Expr *) result);

    /* Also convert to implicit-AND format */
    result = make_ands_implicit((Expr *) result);

    /* May as well fix opfuncids too */
    fix_opfuncids((Node *) result);

    /* Now save a copy of the completed tree in the relcache entry. */
    oldcxt = MemoryContextSwitchTo(relation->rd_indexcxt);
    relation->rd_indpred = (List *) copyObject(result);
    MemoryContextSwitchTo(oldcxt);

    return result;
}

Oid RelationGetOidIndex ( Relation  relation  ) 

Definition at line 3636 of file relcache.c.

References Assert, list_free(), RelationData::rd_indexvalid, RelationData::rd_oidindex, RelationData::rd_rel, and RelationGetIndexList().

Referenced by GetNewOid().

{
    List       *ilist;

    /*
     * If relation doesn't have OIDs at all, caller is probably confused. (We
     * could just silently return InvalidOid, but it seems better to throw an
     * assertion.)
     */
    Assert(relation->rd_rel->relhasoids);

    if (relation->rd_indexvalid == 0)
    {
        /* RelationGetIndexList does the heavy lifting. */
        ilist = RelationGetIndexList(relation);
        list_free(ilist);
        Assert(relation->rd_indexvalid != 0);
    }

    return relation->rd_oidindex;
}

Relation RelationIdGetRelation ( Oid  relationId  ) 

Definition at line 1582 of file relcache.c.

References RelationData::rd_isvalid, RelationData::rd_rel, RelationBuildDesc(), RelationClearRelation(), RelationIdCacheLookup, RelationIncrementReferenceCount(), RelationIsValid, RelationReloadIndexInfo(), and RELKIND_INDEX.

Referenced by relation_open(), and try_relation_open().

{
    Relation    rd;

    /*
     * first try to find reldesc in the cache
     */
    RelationIdCacheLookup(relationId, rd);

    if (RelationIsValid(rd))
    {
        RelationIncrementReferenceCount(rd);
        /* revalidate cache entry if necessary */
        if (!rd->rd_isvalid)
        {
            /*
             * Indexes only have a limited number of possible schema changes,
             * and we don't want to use the full-blown procedure because it's
             * a headache for indexes that reload itself depends on.
             */
            if (rd->rd_rel->relkind == RELKIND_INDEX)
                RelationReloadIndexInfo(rd);
            else
                RelationClearRelation(rd, true);
        }
        return rd;
    }

    /*
     * no reldesc in the cache, so have RelationBuildDesc() build one and add
     * it.
     */
    rd = RelationBuildDesc(relationId, true);
    if (RelationIsValid(rd))
        RelationIncrementReferenceCount(rd);
    return rd;
}

bool RelationIdIsInInitFile ( Oid  relationId  ) 

Definition at line 4719 of file relcache.c.

References list_member_oid().

Referenced by RegisterRelcacheInvalidation().

{
    return list_member_oid(initFileRelationIds, relationId);
}

void RelationInitIndexAccessInfo ( Relation  relation  ) 

Definition at line 1018 of file relcache.c.

References ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE, ALLOCSET_SMALL_MINSIZE, AllocSetContextCreate(), AMOID, Anum_pg_index_indclass, Anum_pg_index_indcollation, Anum_pg_index_indoption, Assert, CacheMemoryContext, DatumGetPointer, elog, ERROR, fastgetattr, GetPgIndexDescriptor(), GETSTRUCT, heap_copytuple(), HeapTupleIsValid, INDEXRELID, IndexSupportInitialize(), MemoryContextAlloc(), MemoryContextAllocZero(), MemoryContextSwitchTo(), ObjectIdGetDatum, RelationData::rd_am, RelationData::rd_amcache, RelationData::rd_aminfo, RelationData::rd_exclops, RelationData::rd_exclprocs, RelationData::rd_exclstrats, RelationData::rd_indcollation, RelationData::rd_index, RelationData::rd_indexcxt, RelationData::rd_indexprs, RelationData::rd_indextuple, RelationData::rd_indoption, RelationData::rd_indpred, RelationData::rd_opcintype, RelationData::rd_opfamily, RelationData::rd_rel, RelationData::rd_support, RelationData::rd_supportinfo, RelationGetRelationName, RelationGetRelid, ReleaseSysCache(), SearchSysCache1, int2vector::values, and oidvector::values.

Referenced by index_create(), and RelationBuildDesc().

{
    HeapTuple   tuple;
    Form_pg_am  aform;
    Datum       indcollDatum;
    Datum       indclassDatum;
    Datum       indoptionDatum;
    bool        isnull;
    oidvector  *indcoll;
    oidvector  *indclass;
    int2vector *indoption;
    MemoryContext indexcxt;
    MemoryContext oldcontext;
    int         natts;
    uint16      amsupport;

    /*
     * Make a copy of the pg_index entry for the index.  Since pg_index
     * contains variable-length and possibly-null fields, we have to do this
     * honestly rather than just treating it as a Form_pg_index struct.
     */
    tuple = SearchSysCache1(INDEXRELID,
                            ObjectIdGetDatum(RelationGetRelid(relation)));
    if (!HeapTupleIsValid(tuple))
        elog(ERROR, "cache lookup failed for index %u",
             RelationGetRelid(relation));
    oldcontext = MemoryContextSwitchTo(CacheMemoryContext);
    relation->rd_indextuple = heap_copytuple(tuple);
    relation->rd_index = (Form_pg_index) GETSTRUCT(relation->rd_indextuple);
    MemoryContextSwitchTo(oldcontext);
    ReleaseSysCache(tuple);

    /*
     * Make a copy of the pg_am entry for the index's access method
     */
    tuple = SearchSysCache1(AMOID, ObjectIdGetDatum(relation->rd_rel->relam));
    if (!HeapTupleIsValid(tuple))
        elog(ERROR, "cache lookup failed for access method %u",
             relation->rd_rel->relam);
    aform = (Form_pg_am) MemoryContextAlloc(CacheMemoryContext, sizeof *aform);
    memcpy(aform, GETSTRUCT(tuple), sizeof *aform);
    ReleaseSysCache(tuple);
    relation->rd_am = aform;

    natts = relation->rd_rel->relnatts;
    if (natts != relation->rd_index->indnatts)
        elog(ERROR, "relnatts disagrees with indnatts for index %u",
             RelationGetRelid(relation));
    amsupport = aform->amsupport;

    /*
     * Make the private context to hold index access info.  The reason we need
     * a context, and not just a couple of pallocs, is so that we won't leak
     * any subsidiary info attached to fmgr lookup records.
     *
     * Context parameters are set on the assumption that it'll probably not
     * contain much data.
     */
    indexcxt = AllocSetContextCreate(CacheMemoryContext,
                                     RelationGetRelationName(relation),
                                     ALLOCSET_SMALL_MINSIZE,
                                     ALLOCSET_SMALL_INITSIZE,
                                     ALLOCSET_SMALL_MAXSIZE);
    relation->rd_indexcxt = indexcxt;

    /*
     * Allocate arrays to hold data
     */
    relation->rd_aminfo = (RelationAmInfo *)
        MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo));

    relation->rd_opfamily = (Oid *)
        MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));
    relation->rd_opcintype = (Oid *)
        MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));

    if (amsupport > 0)
    {
        int         nsupport = natts * amsupport;

        relation->rd_support = (RegProcedure *)
            MemoryContextAllocZero(indexcxt, nsupport * sizeof(RegProcedure));
        relation->rd_supportinfo = (FmgrInfo *)
            MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo));
    }
    else
    {
        relation->rd_support = NULL;
        relation->rd_supportinfo = NULL;
    }

    relation->rd_indcollation = (Oid *)
        MemoryContextAllocZero(indexcxt, natts * sizeof(Oid));

    relation->rd_indoption = (int16 *)
        MemoryContextAllocZero(indexcxt, natts * sizeof(int16));

    /*
     * indcollation cannot be referenced directly through the C struct,
     * because it comes after the variable-width indkey field.  Must extract
     * the datum the hard way...
     */
    indcollDatum = fastgetattr(relation->rd_indextuple,
                               Anum_pg_index_indcollation,
                               GetPgIndexDescriptor(),
                               &isnull);
    Assert(!isnull);
    indcoll = (oidvector *) DatumGetPointer(indcollDatum);
    memcpy(relation->rd_indcollation, indcoll->values, natts * sizeof(Oid));

    /*
     * indclass cannot be referenced directly through the C struct, because it
     * comes after the variable-width indkey field.  Must extract the datum
     * the hard way...
     */
    indclassDatum = fastgetattr(relation->rd_indextuple,
                                Anum_pg_index_indclass,
                                GetPgIndexDescriptor(),
                                &isnull);
    Assert(!isnull);
    indclass = (oidvector *) DatumGetPointer(indclassDatum);

    /*
     * Fill the support procedure OID array, as well as the info about
     * opfamilies and opclass input types.  (aminfo and supportinfo are left
     * as zeroes, and are filled on-the-fly when used)
     */
    IndexSupportInitialize(indclass, relation->rd_support,
                           relation->rd_opfamily, relation->rd_opcintype,
                           amsupport, natts);

    /*
     * Similarly extract indoption and copy it to the cache entry
     */
    indoptionDatum = fastgetattr(relation->rd_indextuple,
                                 Anum_pg_index_indoption,
                                 GetPgIndexDescriptor(),
                                 &isnull);
    Assert(!isnull);
    indoption = (int2vector *) DatumGetPointer(indoptionDatum);
    memcpy(relation->rd_indoption, indoption->values, natts * sizeof(int16));

    /*
     * expressions, predicate, exclusion caches will be filled later
     */
    relation->rd_indexprs = NIL;
    relation->rd_indpred = NIL;
    relation->rd_exclops = NULL;
    relation->rd_exclprocs = NULL;
    relation->rd_exclstrats = NULL;
    relation->rd_amcache = NULL;
}

void RelationSetIndexList ( Relation  relation,
List indexIds,
Oid  oidIndex 
)

Definition at line 3612 of file relcache.c.

References Assert, CacheMemoryContext, EOXactListAdd, list_copy(), list_free(), MemoryContextSwitchTo(), RelationData::rd_indexlist, RelationData::rd_indexvalid, RelationData::rd_isnailed, and RelationData::rd_oidindex.

Referenced by reindex_relation().

{
    MemoryContext oldcxt;

    Assert(relation->rd_isnailed);
    /* Copy the list into the cache context (could fail for lack of mem) */
    oldcxt = MemoryContextSwitchTo(CacheMemoryContext);
    indexIds = list_copy(indexIds);
    MemoryContextSwitchTo(oldcxt);
    /* Okay to replace old list */
    list_free(relation->rd_indexlist);
    relation->rd_indexlist = indexIds;
    relation->rd_oidindex = oidIndex;
    relation->rd_indexvalid = 2;    /* mark list as forced */
    /* Flag relation as needing eoxact cleanup (to reset the list) */
    EOXactListAdd(relation);
}

void RelationSetNewRelfilenode ( Relation  relation,
TransactionId  freezeXid,
MultiXactId  minmulti 
)

Definition at line 2753 of file relcache.c.

References Assert, RelFileNodeBackend::backend, CatalogUpdateIndexes(), CommandCounterIncrement(), elog, EOXactListAdd, ERROR, GetCurrentSubTransactionId(), GetNewRelFileNode(), GETSTRUCT, heap_close, heap_freetuple(), heap_open(), HeapTupleIsValid, InvalidTransactionId, MultiXactIdIsValid, RelFileNodeBackend::node, NULL, ObjectIdGetDatum, RelationData::rd_backend, RelationData::rd_newRelfilenodeSubid, RelationData::rd_node, RelationData::rd_rel, RelationCreateStorage(), RelationDropStorage(), RelationGetRelid, RelationIsMapped, RelationMapUpdateMap(), RelationRelationId, RELKIND_INDEX, RELKIND_SEQUENCE, RelFileNode::relNode, RELOID, RowExclusiveLock, SearchSysCacheCopy1, simple_heap_update(), smgrclosenode(), HeapTupleData::t_self, and TransactionIdIsNormal.

Referenced by ExecuteTruncate(), reindex_index(), and ResetSequence().

{
    Oid         newrelfilenode;
    RelFileNodeBackend newrnode;
    Relation    pg_class;
    HeapTuple   tuple;
    Form_pg_class classform;

    /* Indexes, sequences must have Invalid frozenxid; other rels must not */
    Assert((relation->rd_rel->relkind == RELKIND_INDEX ||
            relation->rd_rel->relkind == RELKIND_SEQUENCE) ?
           freezeXid == InvalidTransactionId :
           TransactionIdIsNormal(freezeXid));
    Assert(TransactionIdIsNormal(freezeXid) == MultiXactIdIsValid(minmulti));

    /* Allocate a new relfilenode */
    newrelfilenode = GetNewRelFileNode(relation->rd_rel->reltablespace, NULL,
                                       relation->rd_rel->relpersistence);

    /*
     * Get a writable copy of the pg_class tuple for the given relation.
     */
    pg_class = heap_open(RelationRelationId, RowExclusiveLock);

    tuple = SearchSysCacheCopy1(RELOID,
                                ObjectIdGetDatum(RelationGetRelid(relation)));
    if (!HeapTupleIsValid(tuple))
        elog(ERROR, "could not find tuple for relation %u",
             RelationGetRelid(relation));
    classform = (Form_pg_class) GETSTRUCT(tuple);

    /*
     * Create storage for the main fork of the new relfilenode.
     *
     * NOTE: any conflict in relfilenode value will be caught here, if
     * GetNewRelFileNode messes up for any reason.
     */
    newrnode.node = relation->rd_node;
    newrnode.node.relNode = newrelfilenode;
    newrnode.backend = relation->rd_backend;
    RelationCreateStorage(newrnode.node, relation->rd_rel->relpersistence);
    smgrclosenode(newrnode);

    /*
     * Schedule unlinking of the old storage at transaction commit.
     */
    RelationDropStorage(relation);

    /*
     * Now update the pg_class row.  However, if we're dealing with a mapped
     * index, pg_class.relfilenode doesn't change; instead we have to send the
     * update to the relation mapper.
     */
    if (RelationIsMapped(relation))
        RelationMapUpdateMap(RelationGetRelid(relation),
                             newrelfilenode,
                             relation->rd_rel->relisshared,
                             false);
    else
        classform->relfilenode = newrelfilenode;

    /* These changes are safe even for a mapped relation */
    if (relation->rd_rel->relkind != RELKIND_SEQUENCE)
    {
        classform->relpages = 0;    /* it's empty until further notice */
        classform->reltuples = 0;
        classform->relallvisible = 0;
    }
    classform->relfrozenxid = freezeXid;
    classform->relminmxid = minmulti;

    simple_heap_update(pg_class, &tuple->t_self, tuple);
    CatalogUpdateIndexes(pg_class, tuple);

    heap_freetuple(tuple);

    heap_close(pg_class, RowExclusiveLock);

    /*
     * Make the pg_class row change visible, as well as the relation map
     * change if any.  This will cause the relcache entry to get updated, too.
     */
    CommandCounterIncrement();

    /*
     * Mark the rel as having been given a new relfilenode in the current
     * (sub) transaction.  This is a hint that can be used to optimize later
     * operations on the rel in the same transaction.
     */
    relation->rd_newRelfilenodeSubid = GetCurrentSubTransactionId();

    /* Flag relation as needing eoxact cleanup (to remove the hint) */
    EOXactListAdd(relation);
}


Variable Documentation