#include "postgres.h"
#include <sys/file.h>
#include <fcntl.h>
#include <unistd.h>
#include "access/htup_details.h"
#include "access/multixact.h"
#include "access/reloptions.h"
#include "access/sysattr.h"
#include "access/transam.h"
#include "access/xact.h"
#include "catalog/catalog.h"
#include "catalog/heap.h"
#include "catalog/index.h"
#include "catalog/indexing.h"
#include "catalog/namespace.h"
#include "catalog/pg_amproc.h"
#include "catalog/pg_attrdef.h"
#include "catalog/pg_authid.h"
#include "catalog/pg_auth_members.h"
#include "catalog/pg_constraint.h"
#include "catalog/pg_database.h"
#include "catalog/pg_namespace.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_rewrite.h"
#include "catalog/pg_tablespace.h"
#include "catalog/pg_trigger.h"
#include "catalog/pg_type.h"
#include "catalog/schemapg.h"
#include "catalog/storage.h"
#include "commands/trigger.h"
#include "common/relpath.h"
#include "miscadmin.h"
#include "optimizer/clauses.h"
#include "optimizer/planmain.h"
#include "optimizer/prep.h"
#include "optimizer/var.h"
#include "rewrite/rewriteDefine.h"
#include "storage/lmgr.h"
#include "storage/smgr.h"
#include "utils/array.h"
#include "utils/builtins.h"
#include "utils/fmgroids.h"
#include "utils/inval.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
#include "utils/relmapper.h"
#include "utils/resowner_private.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
Go to the source code of this file.
#define EOXactListAdd | ( | rel | ) |
do { \ if (eoxact_list_len < MAX_EOXACT_LIST) \ eoxact_list[eoxact_list_len++] = (rel)->rd_id; \ else \ eoxact_list_overflowed = true; \ } while (0)
Definition at line 157 of file relcache.c.
Referenced by RelationBuildLocalRelation(), RelationSetIndexList(), and RelationSetNewRelfilenode().
#define INITRELCACHESIZE 400 |
Definition at line 2862 of file relcache.c.
Referenced by RelationCacheInitialize().
#define MAX_EOXACT_LIST 32 |
Definition at line 152 of file relcache.c.
#define NUM_CRITICAL_LOCAL_INDEXES 7 |
Referenced by load_relcache_init_file().
#define NUM_CRITICAL_LOCAL_RELS 4 |
Referenced by load_relcache_init_file().
#define NUM_CRITICAL_SHARED_INDEXES 5 |
Referenced by load_relcache_init_file().
#define NUM_CRITICAL_SHARED_RELS 3 |
Referenced by load_relcache_init_file().
#define RelationCacheDelete | ( | RELATION | ) |
do { \ RelIdCacheEnt *idhentry; \ idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \ (void *) &(RELATION->rd_id), \ HASH_REMOVE, NULL); \ if (idhentry == NULL) \ elog(WARNING, "trying to delete a rd_id reldesc that does not exist"); \ } while(0)
Definition at line 191 of file relcache.c.
Referenced by RelationClearRelation().
#define RelationCacheInsert | ( | RELATION | ) |
do { \ RelIdCacheEnt *idhentry; bool found; \ idhentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \ (void *) &(RELATION->rd_id), \ HASH_ENTER, &found); \ /* used to give notice if found -- now just keep quiet */ \ idhentry->reldesc = RELATION; \ } while(0)
Definition at line 169 of file relcache.c.
Referenced by formrdesc(), load_relcache_init_file(), RelationBuildDesc(), and RelationBuildLocalRelation().
#define RelationIdCacheLookup | ( | ID, | ||
RELATION | ||||
) |
do { \ RelIdCacheEnt *hentry; \ hentry = (RelIdCacheEnt*)hash_search(RelationIdCache, \ (void *) &(ID), \ HASH_FIND, NULL); \ if (hentry) \ RELATION = hentry->reldesc; \ else \ RELATION = NULL; \ } while(0)
Definition at line 179 of file relcache.c.
Referenced by RelationCacheInvalidateEntry(), RelationCloseSmgrByOid(), RelationForgetRelation(), and RelationIdGetRelation().
#define RELCACHE_INIT_FILEMAGIC 0x573266 |
Definition at line 86 of file relcache.c.
Referenced by load_relcache_init_file().
#define RELCACHE_INIT_FILENAME "pg_internal.init" |
Definition at line 84 of file relcache.c.
Referenced by load_relcache_init_file(), RelationCacheInitFilePreInvalidate(), RelationCacheInitFileRemove(), RelationCacheInitFileRemoveInDir(), and write_relcache_init_file().
#define SWAPFIELD | ( | fldtype, | ||
fldname | ||||
) |
do { \ fldtype _tmp = newrel->fldname; \ newrel->fldname = relation->fldname; \ relation->fldname = _tmp; \ } while (0)
Referenced by RelationClearRelation().
typedef struct opclasscacheent OpClassCacheEnt |
typedef struct relidcacheent RelIdCacheEnt |
static Relation AllocateRelationDesc | ( | Form_pg_class | relp | ) | [static] |
Definition at line 334 of file relcache.c.
References CacheMemoryContext, CLASS_TUPLE_SIZE, CreateTemplateTupleDesc(), MemoryContextSwitchTo(), palloc(), palloc0(), RelationData::rd_att, RelationData::rd_rel, RelationData::rd_smgr, and tupleDesc::tdrefcount.
Referenced by RelationBuildDesc().
{ Relation relation; MemoryContext oldcxt; Form_pg_class relationForm; /* Relcache entries must live in CacheMemoryContext */ oldcxt = MemoryContextSwitchTo(CacheMemoryContext); /* * allocate and zero space for new relation descriptor */ relation = (Relation) palloc0(sizeof(RelationData)); /* make sure relation is marked as having no open file yet */ relation->rd_smgr = NULL; /* * Copy the relation tuple form * * We only allocate space for the fixed fields, ie, CLASS_TUPLE_SIZE. The * variable-length fields (relacl, reloptions) are NOT stored in the * relcache --- there'd be little point in it, since we don't copy the * tuple's nulls bitmap and hence wouldn't know if the values are valid. * Bottom line is that relacl *cannot* be retrieved from the relcache. Get * it from the syscache if you need it. The same goes for the original * form of reloptions (however, we do store the parsed form of reloptions * in rd_options). */ relationForm = (Form_pg_class) palloc(CLASS_TUPLE_SIZE); memcpy(relationForm, relp, CLASS_TUPLE_SIZE); /* initialize relation tuple form */ relation->rd_rel = relationForm; /* and allocate attribute tuple form storage */ relation->rd_att = CreateTemplateTupleDesc(relationForm->relnatts, relationForm->relhasoids); /* which we mark as a reference-counted tupdesc */ relation->rd_att->tdrefcount = 1; MemoryContextSwitchTo(oldcxt); return relation; }
static void AtEOSubXact_cleanup | ( | Relation | relation, | |
bool | isCommit, | |||
SubTransactionId | mySubid, | |||
SubTransactionId | parentSubid | |||
) | [static] |
Definition at line 2485 of file relcache.c.
References list_free(), RelationData::rd_createSubid, RelationData::rd_indexlist, RelationData::rd_indexvalid, RelationData::rd_newRelfilenodeSubid, RelationData::rd_oidindex, and RelationClearRelation().
Referenced by AtEOSubXact_RelationCache().
{ /* * Is it a relation created in the current subtransaction? * * During subcommit, mark it as belonging to the parent, instead. * During subabort, simply delete the relcache entry. */ if (relation->rd_createSubid == mySubid) { if (isCommit) relation->rd_createSubid = parentSubid; else { RelationClearRelation(relation, false); return; } } /* * Likewise, update or drop any new-relfilenode-in-subtransaction * hint. */ if (relation->rd_newRelfilenodeSubid == mySubid) { if (isCommit) relation->rd_newRelfilenodeSubid = parentSubid; else relation->rd_newRelfilenodeSubid = InvalidSubTransactionId; } /* * Flush any temporary index list. */ if (relation->rd_indexvalid == 2) { list_free(relation->rd_indexlist); relation->rd_indexlist = NIL; relation->rd_oidindex = InvalidOid; relation->rd_indexvalid = 0; } }
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 */ }
Definition at line 2366 of file relcache.c.
References Assert, InvalidSubTransactionId, IsBootstrapProcessingMode, list_free(), RelationData::rd_createSubid, RelationData::rd_indexlist, RelationData::rd_indexvalid, RelationData::rd_isnailed, RelationData::rd_newRelfilenodeSubid, RelationData::rd_oidindex, RelationData::rd_refcnt, and RelationClearRelation().
Referenced by AtEOXact_RelationCache().
{ /* * The relcache entry's ref count should be back to its normal * not-in-a-transaction state: 0 unless it's nailed in cache. * * In bootstrap mode, this is NOT true, so don't check it --- the * bootstrap code expects relations to stay open across start/commit * transaction calls. (That seems bogus, but it's not worth fixing.) * * Note: ideally this check would be applied to every relcache entry, * not just those that have eoxact work to do. But it's not worth * forcing a scan of the whole relcache just for this. (Moreover, * doing so would mean that assert-enabled testing never tests the * hash_search code path above, which seems a bad idea.) */ #ifdef USE_ASSERT_CHECKING if (!IsBootstrapProcessingMode()) { int expected_refcnt; expected_refcnt = relation->rd_isnailed ? 1 : 0; Assert(relation->rd_refcnt == expected_refcnt); } #endif /* * Is it a relation created in the current transaction? * * During commit, reset the flag to zero, since we are now out of the * creating transaction. During abort, simply delete the relcache * entry --- it isn't interesting any longer. (NOTE: if we have * forgotten the new-ness of a new relation due to a forced cache * flush, the entry will get deleted anyway by shared-cache-inval * processing of the aborted pg_class insertion.) */ if (relation->rd_createSubid != InvalidSubTransactionId) { if (isCommit) relation->rd_createSubid = InvalidSubTransactionId; else { RelationClearRelation(relation, false); return; } } /* * Likewise, reset the hint about the relfilenode being new. */ relation->rd_newRelfilenodeSubid = InvalidSubTransactionId; /* * Flush any temporary index list. */ if (relation->rd_indexvalid == 2) { list_free(relation->rd_indexlist); relation->rd_indexlist = NIL; relation->rd_oidindex = InvalidOid; relation->rd_indexvalid = 0; } }
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; }
static void AttrDefaultFetch | ( | Relation | relation | ) | [static] |
Definition at line 3312 of file relcache.c.
References AccessShareLock, attrDefault::adbin, attrDefault::adnum, Anum_pg_attrdef_adbin, Anum_pg_attrdef_adrelid, AttrDefaultIndexId, AttrDefaultRelationId, tupleDesc::attrs, BTEqualStrategyNumber, CacheMemoryContext, tupleDesc::constr, tupleConstr::defval, elog, fastgetattr, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, i, MemoryContextStrdup(), NameStr, NULL, tupleConstr::num_defval, ObjectIdGetDatum, RelationData::rd_att, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), TextDatumGetCString, val, and WARNING.
Referenced by RelationBuildTupleDesc().
{ AttrDefault *attrdef = relation->rd_att->constr->defval; int ndef = relation->rd_att->constr->num_defval; Relation adrel; SysScanDesc adscan; ScanKeyData skey; HeapTuple htup; Datum val; bool isnull; int found; int i; ScanKeyInit(&skey, Anum_pg_attrdef_adrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(relation))); adrel = heap_open(AttrDefaultRelationId, AccessShareLock); adscan = systable_beginscan(adrel, AttrDefaultIndexId, true, SnapshotNow, 1, &skey); found = 0; while (HeapTupleIsValid(htup = systable_getnext(adscan))) { Form_pg_attrdef adform = (Form_pg_attrdef) GETSTRUCT(htup); for (i = 0; i < ndef; i++) { if (adform->adnum != attrdef[i].adnum) continue; if (attrdef[i].adbin != NULL) elog(WARNING, "multiple attrdef records found for attr %s of rel %s", NameStr(relation->rd_att->attrs[adform->adnum - 1]->attname), RelationGetRelationName(relation)); else found++; val = fastgetattr(htup, Anum_pg_attrdef_adbin, adrel->rd_att, &isnull); if (isnull) elog(WARNING, "null adbin for attr %s of rel %s", NameStr(relation->rd_att->attrs[adform->adnum - 1]->attname), RelationGetRelationName(relation)); else attrdef[i].adbin = MemoryContextStrdup(CacheMemoryContext, TextDatumGetCString(val)); break; } if (i >= ndef) elog(WARNING, "unexpected attrdef record found for attr %d of rel %s", adform->adnum, RelationGetRelationName(relation)); } systable_endscan(adscan); heap_close(adrel, AccessShareLock); if (found != ndef) elog(WARNING, "%d attrdef record(s) missing for rel %s", ndef - found, RelationGetRelationName(relation)); }
static TupleDesc BuildHardcodedDescriptor | ( | int | natts, | |
const FormData_pg_attribute * | attrs, | |||
bool | hasoids | |||
) | [static] |
Definition at line 3250 of file relcache.c.
References ATTRIBUTE_FIXED_PART_SIZE, tupleDesc::attrs, CacheMemoryContext, CreateTemplateTupleDesc(), i, MemoryContextSwitchTo(), tupleDesc::tdtypeid, and tupleDesc::tdtypmod.
Referenced by GetPgClassDescriptor(), and GetPgIndexDescriptor().
{ TupleDesc result; MemoryContext oldcxt; int i; oldcxt = MemoryContextSwitchTo(CacheMemoryContext); result = CreateTemplateTupleDesc(natts, hasoids); result->tdtypeid = RECORDOID; /* not right, but we don't care */ result->tdtypmod = -1; for (i = 0; i < natts; i++) { memcpy(result->attrs[i], &attrs[i], ATTRIBUTE_FIXED_PART_SIZE); /* make sure attcacheoff is valid */ result->attrs[i]->attcacheoff = -1; } /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */ result->attrs[0]->attcacheoff = 0; /* Note: we don't bother to set up a TupleConstr entry */ MemoryContextSwitchTo(oldcxt); return result; }
static void CheckConstraintFetch | ( | Relation | relation | ) | [static] |
Definition at line 3380 of file relcache.c.
References AccessShareLock, Anum_pg_constraint_conbin, Anum_pg_constraint_conrelid, BTEqualStrategyNumber, CacheMemoryContext, constrCheck::ccbin, constrCheck::ccname, constrCheck::ccnoinherit, constrCheck::ccvalid, tupleConstr::check, tupleDesc::constr, CONSTRAINT_CHECK, ConstraintRelationId, ConstraintRelidIndexId, elog, ERROR, fastgetattr, GETSTRUCT, heap_close, heap_open(), HeapTupleIsValid, MemoryContextStrdup(), NameStr, tupleConstr::num_check, ObjectIdGetDatum, RelationData::rd_att, RelationGetRelationName, RelationGetRelid, ScanKeyInit(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), TextDatumGetCString, and val.
Referenced by RelationBuildTupleDesc().
{ ConstrCheck *check = relation->rd_att->constr->check; int ncheck = relation->rd_att->constr->num_check; Relation conrel; SysScanDesc conscan; ScanKeyData skey[1]; HeapTuple htup; Datum val; bool isnull; int found = 0; ScanKeyInit(&skey[0], Anum_pg_constraint_conrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(relation))); conrel = heap_open(ConstraintRelationId, AccessShareLock); conscan = systable_beginscan(conrel, ConstraintRelidIndexId, true, SnapshotNow, 1, skey); while (HeapTupleIsValid(htup = systable_getnext(conscan))) { Form_pg_constraint conform = (Form_pg_constraint) GETSTRUCT(htup); /* We want check constraints only */ if (conform->contype != CONSTRAINT_CHECK) continue; if (found >= ncheck) elog(ERROR, "unexpected constraint record found for rel %s", RelationGetRelationName(relation)); check[found].ccvalid = conform->convalidated; check[found].ccnoinherit = conform->connoinherit; check[found].ccname = MemoryContextStrdup(CacheMemoryContext, NameStr(conform->conname)); /* Grab and test conbin is actually set */ val = fastgetattr(htup, Anum_pg_constraint_conbin, conrel->rd_att, &isnull); if (isnull) elog(ERROR, "null conbin for rel %s", RelationGetRelationName(relation)); check[found].ccbin = MemoryContextStrdup(CacheMemoryContext, TextDatumGetCString(val)); found++; } systable_endscan(conscan); heap_close(conrel, AccessShareLock); if (found != ncheck) elog(ERROR, "%d constraint record(s) missing for rel %s", ncheck - found, RelationGetRelationName(relation)); }
Definition at line 776 of file relcache.c.
References RewriteRule::actions, RewriteRule::attrno, RewriteRule::enabled, equal(), RewriteRule::event, i, RewriteRule::isInstead, NULL, RuleLock::numLocks, RewriteRule::qual, RewriteRule::ruleId, and RuleLock::rules.
Referenced by RelationClearRelation().
{ int i; /* * As of 7.3 we assume the rule ordering is repeatable, because * RelationBuildRuleLock should read 'em in a consistent order. So just * compare corresponding slots. */ if (rlock1 != NULL) { if (rlock2 == NULL) return false; if (rlock1->numLocks != rlock2->numLocks) return false; for (i = 0; i < rlock1->numLocks; i++) { RewriteRule *rule1 = rlock1->rules[i]; RewriteRule *rule2 = rlock2->rules[i]; if (rule1->ruleId != rule2->ruleId) return false; if (rule1->event != rule2->event) return false; if (rule1->attrno != rule2->attrno) return false; if (rule1->enabled != rule2->enabled) return false; if (rule1->isInstead != rule2->isInstead) return false; if (!equal(rule1->qual, rule2->qual)) return false; if (!equal(rule1->actions, rule2->actions)) return false; } } else if (rlock2 != NULL) return false; return true; }
int errtable | ( | Relation | rel | ) |
Definition at line 4038 of file relcache.c.
References err_generic_string(), get_namespace_name(), PG_DIAG_SCHEMA_NAME, PG_DIAG_TABLE_NAME, RelationGetNamespace, and RelationGetRelationName.
Referenced by errtablecolname(), and errtableconstraint().
{ err_generic_string(PG_DIAG_SCHEMA_NAME, get_namespace_name(RelationGetNamespace(rel))); err_generic_string(PG_DIAG_TABLE_NAME, RelationGetRelationName(rel)); return 0; /* return value does not matter */ }
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 | |||
) |
Definition at line 4092 of file relcache.c.
References err_generic_string(), errtable(), and PG_DIAG_CONSTRAINT_NAME.
Referenced by _bt_buildadd(), _bt_check_unique(), _bt_findinsertloc(), ATRewriteTable(), check_exclusion_constraint(), comparetup_index_btree(), ExecConstraints(), RI_FKey_check(), RI_Initial_Check(), ri_ReportViolation(), and validateCheckConstraint().
{ errtable(rel); err_generic_string(PG_DIAG_CONSTRAINT_NAME, conname); return 0; /* return value does not matter */ }
static void formrdesc | ( | const char * | relationName, | |
Oid | relationReltype, | |||
bool | isshared, | |||
bool | hasoids, | |||
int | natts, | |||
const FormData_pg_attribute * | attrs | |||
) | [static] |
Definition at line 1405 of file relcache.c.
References ATTRIBUTE_FIXED_PART_SIZE, tupleDesc::attrs, CLASS_TUPLE_SIZE, tupleDesc::constr, CreateTemplateTupleDesc(), tupleConstr::has_not_null, i, IsBootstrapProcessingMode, namestrcpy(), palloc0(), 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, RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationMapUpdateMap(), tupleDesc::tdrefcount, tupleDesc::tdtypeid, and tupleDesc::tdtypmod.
Referenced by RelationCacheInitializePhase2(), and RelationCacheInitializePhase3().
{ Relation relation; int i; bool has_not_null; /* * allocate new relation desc, clear all fields of reldesc */ relation = (Relation) palloc0(sizeof(RelationData)); /* make sure relation is marked as having no open file yet */ relation->rd_smgr = NULL; /* * initialize reference count: 1 because it is nailed in cache */ relation->rd_refcnt = 1; /* * all entries built with this routine are nailed-in-cache; none are for * new or temp relations. */ relation->rd_isnailed = true; relation->rd_createSubid = InvalidSubTransactionId; relation->rd_newRelfilenodeSubid = InvalidSubTransactionId; relation->rd_backend = InvalidBackendId; relation->rd_islocaltemp = false; /* * initialize relation tuple form * * The data we insert here is pretty incomplete/bogus, but it'll serve to * get us launched. RelationCacheInitializePhase3() will read the real * data from pg_class and replace what we've done here. Note in * particular that relowner is left as zero; this cues * RelationCacheInitializePhase3 that the real data isn't there yet. */ relation->rd_rel = (Form_pg_class) palloc0(CLASS_TUPLE_SIZE); namestrcpy(&relation->rd_rel->relname, relationName); relation->rd_rel->relnamespace = PG_CATALOG_NAMESPACE; relation->rd_rel->reltype = relationReltype; /* * It's important to distinguish between shared and non-shared relations, * even at bootstrap time, to make sure we know where they are stored. */ relation->rd_rel->relisshared = isshared; if (isshared) relation->rd_rel->reltablespace = GLOBALTABLESPACE_OID; /* formrdesc is used only for permanent relations */ relation->rd_rel->relpersistence = RELPERSISTENCE_PERMANENT; relation->rd_rel->relpages = 0; relation->rd_rel->reltuples = 0; relation->rd_rel->relallvisible = 0; relation->rd_rel->relkind = RELKIND_RELATION; relation->rd_rel->relhasoids = hasoids; relation->rd_rel->relnatts = (int16) natts; /* * initialize attribute tuple form * * Unlike the case with the relation tuple, this data had better be right * because it will never be replaced. The data comes from * src/include/catalog/ headers via genbki.pl. */ relation->rd_att = CreateTemplateTupleDesc(natts, hasoids); relation->rd_att->tdrefcount = 1; /* mark as refcounted */ relation->rd_att->tdtypeid = relationReltype; relation->rd_att->tdtypmod = -1; /* unnecessary, but... */ /* * initialize tuple desc info */ has_not_null = false; for (i = 0; i < natts; i++) { memcpy(relation->rd_att->attrs[i], &attrs[i], ATTRIBUTE_FIXED_PART_SIZE); has_not_null |= attrs[i].attnotnull; /* make sure attcacheoff is valid */ relation->rd_att->attrs[i]->attcacheoff = -1; } /* initialize first attribute's attcacheoff, cf RelationBuildTupleDesc */ relation->rd_att->attrs[0]->attcacheoff = 0; /* mark not-null status */ if (has_not_null) { TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr)); constr->has_not_null = true; relation->rd_att->constr = constr; } /* * initialize relation id from info in att array (my, this is ugly) */ RelationGetRelid(relation) = relation->rd_att->attrs[0]->attrelid; /* * All relations made with formrdesc are mapped. This is necessarily so * because there is no other way to know what filenode they currently * have. In bootstrap mode, add them to the initial relation mapper data, * specifying that the initial filenode is the same as the OID. */ relation->rd_rel->relfilenode = InvalidOid; if (IsBootstrapProcessingMode()) RelationMapUpdateMap(RelationGetRelid(relation), RelationGetRelid(relation), isshared, true); /* * initialize the relation lock manager information */ RelationInitLockInfo(relation); /* see lmgr.c */ /* * initialize physical addressing information for the relation */ RelationInitPhysicalAddr(relation); relation->rd_ispopulated = true; /* * initialize the rel-has-index flag, using hardwired knowledge */ if (IsBootstrapProcessingMode()) { /* In bootstrap mode, we have no indexes */ relation->rd_rel->relhasindex = false; } else { /* Otherwise, all the rels formrdesc is used for have indexes */ relation->rd_rel->relhasindex = true; } /* * add new reldesc to relcache */ RelationCacheInsert(relation); /* It's fully valid */ relation->rd_isvalid = true; }
static TupleDesc GetPgClassDescriptor | ( | void | ) | [static] |
Definition at line 3281 of file relcache.c.
References BuildHardcodedDescriptor(), Desc_pg_class, Natts_pg_class, and NULL.
Referenced by RelationParseRelOptions().
{ static TupleDesc pgclassdesc = NULL; /* Already done? */ if (pgclassdesc == NULL) pgclassdesc = BuildHardcodedDescriptor(Natts_pg_class, Desc_pg_class, true); return pgclassdesc; }
static TupleDesc GetPgIndexDescriptor | ( | void | ) | [static] |
Definition at line 3295 of file relcache.c.
References BuildHardcodedDescriptor(), Desc_pg_index, Natts_pg_index, and NULL.
Referenced by RelationGetIndexExpressions(), RelationGetIndexList(), RelationGetIndexPredicate(), and RelationInitIndexAccessInfo().
{ static TupleDesc pgindexdesc = NULL; /* Already done? */ if (pgindexdesc == NULL) pgindexdesc = BuildHardcodedDescriptor(Natts_pg_index, Desc_pg_index, false); return pgindexdesc; }
static void IndexSupportInitialize | ( | oidvector * | indclass, | |
RegProcedure * | indexSupport, | |||
Oid * | opFamily, | |||
Oid * | opcInType, | |||
StrategyNumber | maxSupportNumber, | |||
AttrNumber | maxAttributeNumber | |||
) | [static] |
Definition at line 1185 of file relcache.c.
References elog, ERROR, LookupOpclassInfo(), OidIsValid, opclasscacheent::opcfamily, opclasscacheent::opcintype, opclasscacheent::supportProcs, and oidvector::values.
Referenced by RelationInitIndexAccessInfo().
{ int attIndex; for (attIndex = 0; attIndex < maxAttributeNumber; attIndex++) { OpClassCacheEnt *opcentry; if (!OidIsValid(indclass->values[attIndex])) elog(ERROR, "bogus pg_index tuple"); /* look up the info for this opclass, using a cache */ opcentry = LookupOpclassInfo(indclass->values[attIndex], maxSupportNumber); /* copy cached data into relcache entry */ opFamily[attIndex] = opcentry->opcfamily; opcInType[attIndex] = opcentry->opcintype; if (maxSupportNumber > 0) memcpy(&indexSupport[attIndex * maxSupportNumber], opcentry->supportProcs, maxSupportNumber * sizeof(RegProcedure)); } }
Definition at line 3568 of file relcache.c.
References lappend_cell_oid(), lcons_oid(), lfirst_oid, linitial_oid, list_head(), lnext, NIL, and NULL.
Referenced by RelationGetIndexList().
{ ListCell *prev; /* Does the datum belong at the front? */ if (list == NIL || datum < linitial_oid(list)) return lcons_oid(datum, list); /* No, so find the entry it belongs after */ prev = list_head(list); for (;;) { ListCell *curr = lnext(prev); if (curr == NULL || datum < lfirst_oid(curr)) break; /* it belongs after 'prev', before 'curr' */ prev = curr; } /* Insert datum into list after 'prev' */ lappend_cell_oid(list, prev, datum); return list; }
Definition at line 3216 of file relcache.c.
References AccessShareLock, elog, LockRelationOid(), NULL, PANIC, RelationData::rd_isnailed, RelationData::rd_refcnt, RelationBuildDesc(), and UnlockRelationOid().
Referenced by RelationCacheInitializePhase3().
{ Relation ird; /* * We must lock the underlying catalog before locking the index to avoid * deadlock, since RelationBuildDesc might well need to read the catalog, * and if anyone else is exclusive-locking this catalog and index they'll * be doing it in that order. */ LockRelationOid(heapoid, AccessShareLock); LockRelationOid(indexoid, AccessShareLock); ird = RelationBuildDesc(indexoid, true); if (ird == NULL) elog(PANIC, "could not open critical system index %u", indexoid); ird->rd_isnailed = true; ird->rd_refcnt = 1; UnlockRelationOid(indexoid, AccessShareLock); UnlockRelationOid(heapoid, AccessShareLock); }
Definition at line 4156 of file relcache.c.
References AllocateFile(), ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE, ALLOCSET_SMALL_MINSIZE, AllocSetContextCreate(), Assert, ATTRIBUTE_FIXED_PART_SIZE, tupleDesc::attrs, CacheMemoryContext, tupleDesc::constr, CreateTemplateTupleDesc(), criticalRelcachesBuilt, criticalSharedRelcachesBuilt, DatabasePath, FreeFile(), GETSTRUCT, tupleConstr::has_not_null, heap_is_matview_init_state(), i, lcons_oid(), MemoryContextAlloc(), MemoryContextAllocZero(), MemSet, NULL, NUM_CRITICAL_LOCAL_INDEXES, NUM_CRITICAL_LOCAL_RELS, NUM_CRITICAL_SHARED_INDEXES, NUM_CRITICAL_SHARED_RELS, palloc(), palloc0(), pfree(), PG_BINARY_R, RelationData::pgstat_info, RelationData::rd_am, RelationData::rd_amcache, RelationData::rd_aminfo, RelationData::rd_att, RelationData::rd_createSubid, RelationData::rd_exclops, RelationData::rd_exclprocs, RelationData::rd_exclstrats, RelationData::rd_fdwroutine, RelationData::rd_indcollation, RelationData::rd_index, RelationData::rd_indexattr, RelationData::rd_indexcxt, RelationData::rd_indexlist, RelationData::rd_indexprs, RelationData::rd_indextuple, RelationData::rd_indexvalid, RelationData::rd_indoption, RelationData::rd_indpred, RelationData::rd_isnailed, RelationData::rd_ispopulated, RelationData::rd_newRelfilenodeSubid, RelationData::rd_oidindex, RelationData::rd_opcintype, RelationData::rd_opfamily, RelationData::rd_options, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_rules, RelationData::rd_rulescxt, RelationData::rd_smgr, RelationData::rd_support, RelationData::rd_supportinfo, RelationCacheInsert, RelationGetRelationName, RelationGetRelid, RelationInitLockInfo(), RelationInitPhysicalAddr(), RELCACHE_INIT_FILEMAGIC, RELCACHE_INIT_FILENAME, RELKIND_INDEX, RELKIND_MATVIEW, repalloc(), snprintf(), HeapTupleData::t_data, tupleDesc::tdrefcount, tupleDesc::tdtypeid, tupleDesc::tdtypmod, RelationData::trigdesc, and VARSIZE.
Referenced by RelationCacheInitializePhase2(), and RelationCacheInitializePhase3().
{ FILE *fp; char initfilename[MAXPGPATH]; Relation *rels; int relno, num_rels, max_rels, nailed_rels, nailed_indexes, magic; int i; if (shared) snprintf(initfilename, sizeof(initfilename), "global/%s", RELCACHE_INIT_FILENAME); else snprintf(initfilename, sizeof(initfilename), "%s/%s", DatabasePath, RELCACHE_INIT_FILENAME); fp = AllocateFile(initfilename, PG_BINARY_R); if (fp == NULL) return false; /* * Read the index relcache entries from the file. Note we will not enter * any of them into the cache if the read fails partway through; this * helps to guard against broken init files. */ max_rels = 100; rels = (Relation *) palloc(max_rels * sizeof(Relation)); num_rels = 0; nailed_rels = nailed_indexes = 0; /* check for correct magic number (compatible version) */ if (fread(&magic, 1, sizeof(magic), fp) != sizeof(magic)) goto read_failed; if (magic != RELCACHE_INIT_FILEMAGIC) goto read_failed; for (relno = 0;; relno++) { Size len; size_t nread; Relation rel; Form_pg_class relform; bool has_not_null; /* first read the relation descriptor length */ nread = fread(&len, 1, sizeof(len), fp); if (nread != sizeof(len)) { if (nread == 0) break; /* end of file */ goto read_failed; } /* safety check for incompatible relcache layout */ if (len != sizeof(RelationData)) goto read_failed; /* allocate another relcache header */ if (num_rels >= max_rels) { max_rels *= 2; rels = (Relation *) repalloc(rels, max_rels * sizeof(Relation)); } rel = rels[num_rels++] = (Relation) palloc(len); /* then, read the Relation structure */ if (fread(rel, 1, len, fp) != len) goto read_failed; /* next read the relation tuple form */ if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) goto read_failed; relform = (Form_pg_class) palloc(len); if (fread(relform, 1, len, fp) != len) goto read_failed; rel->rd_rel = relform; /* initialize attribute tuple forms */ rel->rd_att = CreateTemplateTupleDesc(relform->relnatts, relform->relhasoids); rel->rd_att->tdrefcount = 1; /* mark as refcounted */ rel->rd_att->tdtypeid = relform->reltype; rel->rd_att->tdtypmod = -1; /* unnecessary, but... */ /* next read all the attribute tuple form data entries */ has_not_null = false; for (i = 0; i < relform->relnatts; i++) { if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) goto read_failed; if (len != ATTRIBUTE_FIXED_PART_SIZE) goto read_failed; if (fread(rel->rd_att->attrs[i], 1, len, fp) != len) goto read_failed; has_not_null |= rel->rd_att->attrs[i]->attnotnull; } /* next read the access method specific field */ if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) goto read_failed; if (len > 0) { rel->rd_options = palloc(len); if (fread(rel->rd_options, 1, len, fp) != len) goto read_failed; if (len != VARSIZE(rel->rd_options)) goto read_failed; /* sanity check */ } else { rel->rd_options = NULL; } /* mark not-null status */ if (has_not_null) { TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr)); constr->has_not_null = true; rel->rd_att->constr = constr; } /* If it's an index, there's more to do */ if (rel->rd_rel->relkind == RELKIND_INDEX) { Form_pg_am am; MemoryContext indexcxt; Oid *opfamily; Oid *opcintype; RegProcedure *support; int nsupport; int16 *indoption; Oid *indcollation; /* Count nailed indexes to ensure we have 'em all */ if (rel->rd_isnailed) nailed_indexes++; /* next, read the pg_index tuple */ if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) goto read_failed; rel->rd_indextuple = (HeapTuple) palloc(len); if (fread(rel->rd_indextuple, 1, len, fp) != len) goto read_failed; /* Fix up internal pointers in the tuple -- see heap_copytuple */ rel->rd_indextuple->t_data = (HeapTupleHeader) ((char *) rel->rd_indextuple + HEAPTUPLESIZE); rel->rd_index = (Form_pg_index) GETSTRUCT(rel->rd_indextuple); /* next, read the access method tuple form */ if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) goto read_failed; am = (Form_pg_am) palloc(len); if (fread(am, 1, len, fp) != len) goto read_failed; rel->rd_am = am; /* * prepare index info context --- parameters should match * RelationInitIndexAccessInfo */ indexcxt = AllocSetContextCreate(CacheMemoryContext, RelationGetRelationName(rel), ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE); rel->rd_indexcxt = indexcxt; /* next, read the vector of opfamily OIDs */ if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) goto read_failed; opfamily = (Oid *) MemoryContextAlloc(indexcxt, len); if (fread(opfamily, 1, len, fp) != len) goto read_failed; rel->rd_opfamily = opfamily; /* next, read the vector of opcintype OIDs */ if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) goto read_failed; opcintype = (Oid *) MemoryContextAlloc(indexcxt, len); if (fread(opcintype, 1, len, fp) != len) goto read_failed; rel->rd_opcintype = opcintype; /* next, read the vector of support procedure OIDs */ if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) goto read_failed; support = (RegProcedure *) MemoryContextAlloc(indexcxt, len); if (fread(support, 1, len, fp) != len) goto read_failed; rel->rd_support = support; /* next, read the vector of collation OIDs */ if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) goto read_failed; indcollation = (Oid *) MemoryContextAlloc(indexcxt, len); if (fread(indcollation, 1, len, fp) != len) goto read_failed; rel->rd_indcollation = indcollation; /* finally, read the vector of indoption values */ if (fread(&len, 1, sizeof(len), fp) != sizeof(len)) goto read_failed; indoption = (int16 *) MemoryContextAlloc(indexcxt, len); if (fread(indoption, 1, len, fp) != len) goto read_failed; rel->rd_indoption = indoption; /* set up zeroed fmgr-info vectors */ rel->rd_aminfo = (RelationAmInfo *) MemoryContextAllocZero(indexcxt, sizeof(RelationAmInfo)); nsupport = relform->relnatts * am->amsupport; rel->rd_supportinfo = (FmgrInfo *) MemoryContextAllocZero(indexcxt, nsupport * sizeof(FmgrInfo)); } else { /* Count nailed rels to ensure we have 'em all */ if (rel->rd_isnailed) nailed_rels++; Assert(rel->rd_index == NULL); Assert(rel->rd_indextuple == NULL); Assert(rel->rd_am == NULL); Assert(rel->rd_indexcxt == NULL); Assert(rel->rd_aminfo == NULL); Assert(rel->rd_opfamily == NULL); Assert(rel->rd_opcintype == NULL); Assert(rel->rd_support == NULL); Assert(rel->rd_supportinfo == NULL); Assert(rel->rd_indoption == NULL); Assert(rel->rd_indcollation == NULL); } /* * Rules and triggers are not saved (mainly because the internal * format is complex and subject to change). They must be rebuilt if * needed by RelationCacheInitializePhase3. This is not expected to * be a big performance hit since few system catalogs have such. Ditto * for index expressions, predicates, exclusion info, and FDW info. */ rel->rd_rules = NULL; rel->rd_rulescxt = NULL; rel->trigdesc = NULL; rel->rd_indexprs = NIL; rel->rd_indpred = NIL; rel->rd_exclops = NULL; rel->rd_exclprocs = NULL; rel->rd_exclstrats = NULL; rel->rd_fdwroutine = NULL; /* * Reset transient-state fields in the relcache entry */ rel->rd_smgr = NULL; if (rel->rd_isnailed) rel->rd_refcnt = 1; else rel->rd_refcnt = 0; rel->rd_indexvalid = 0; rel->rd_indexlist = NIL; rel->rd_indexattr = NULL; rel->rd_oidindex = InvalidOid; rel->rd_createSubid = InvalidSubTransactionId; rel->rd_newRelfilenodeSubid = InvalidSubTransactionId; rel->rd_amcache = NULL; MemSet(&rel->pgstat_info, 0, sizeof(rel->pgstat_info)); /* * Recompute lock and physical addressing info. This is needed in * case the pg_internal.init file was copied from some other database * by CREATE DATABASE. */ RelationInitLockInfo(rel); RelationInitPhysicalAddr(rel); if (rel->rd_rel->relkind == RELKIND_MATVIEW && heap_is_matview_init_state(rel)) rel->rd_ispopulated = false; else rel->rd_ispopulated = true; } /* * We reached the end of the init file without apparent problem. Did we * get the right number of nailed items? (This is a useful crosscheck in * case the set of critical rels or indexes changes.) */ if (shared) { if (nailed_rels != NUM_CRITICAL_SHARED_RELS || nailed_indexes != NUM_CRITICAL_SHARED_INDEXES) goto read_failed; } else { if (nailed_rels != NUM_CRITICAL_LOCAL_RELS || nailed_indexes != NUM_CRITICAL_LOCAL_INDEXES) goto read_failed; } /* * OK, all appears well. * * Now insert all the new relcache entries into the cache. */ for (relno = 0; relno < num_rels; relno++) { RelationCacheInsert(rels[relno]); /* also make a list of their OIDs, for RelationIdIsInInitFile */ if (!shared) initFileRelationIds = lcons_oid(RelationGetRelid(rels[relno]), initFileRelationIds); } pfree(rels); FreeFile(fp); if (shared) criticalSharedRelcachesBuilt = true; else criticalRelcachesBuilt = true; return true; /* * init file is broken, so do it the hard way. We don't bother trying to * free the clutter we just allocated; it's not in the relcache so it * won't hurt. */ read_failed: pfree(rels); FreeFile(fp); return false; }
static OpClassCacheEnt * LookupOpclassInfo | ( | Oid | operatorClassOid, | |
StrategyNumber | numSupport | |||
) | [static] |
Definition at line 1236 of file relcache.c.
References AccessMethodProcedureIndexId, AccessMethodProcedureRelationId, AccessShareLock, Anum_pg_amproc_amprocfamily, Anum_pg_amproc_amproclefttype, Anum_pg_amproc_amprocrighttype, Assert, BTEqualStrategyNumber, CacheMemoryContext, CreateCacheMemoryContext(), criticalRelcachesBuilt, elog, HASHCTL::entrysize, ERROR, GETSTRUCT, HASHCTL::hash, hash_create(), HASH_ELEM, HASH_FUNCTION, hash_search(), heap_close, heap_open(), HeapTupleIsValid, HASHCTL::keysize, MemoryContextAllocZero(), MemSet, NULL, opclasscacheent::numSupport, ObjectIdAttributeNumber, ObjectIdGetDatum, OID_BTREE_OPS_OID, opclasscacheent::opcfamily, opclasscacheent::opcintype, OpclassOidIndexId, OperatorClassRelationId, ScanKeyInit(), SnapshotNow, opclasscacheent::supportProcs, systable_beginscan(), systable_endscan(), systable_getnext(), and opclasscacheent::valid.
Referenced by IndexSupportInitialize().
{ OpClassCacheEnt *opcentry; bool found; Relation rel; SysScanDesc scan; ScanKeyData skey[3]; HeapTuple htup; bool indexOK; if (OpClassCache == NULL) { /* First time through: initialize the opclass cache */ HASHCTL ctl; MemSet(&ctl, 0, sizeof(ctl)); ctl.keysize = sizeof(Oid); ctl.entrysize = sizeof(OpClassCacheEnt); ctl.hash = oid_hash; OpClassCache = hash_create("Operator class cache", 64, &ctl, HASH_ELEM | HASH_FUNCTION); /* Also make sure CacheMemoryContext exists */ if (!CacheMemoryContext) CreateCacheMemoryContext(); } opcentry = (OpClassCacheEnt *) hash_search(OpClassCache, (void *) &operatorClassOid, HASH_ENTER, &found); if (!found) { /* Need to allocate memory for new entry */ opcentry->valid = false; /* until known OK */ opcentry->numSupport = numSupport; if (numSupport > 0) opcentry->supportProcs = (RegProcedure *) MemoryContextAllocZero(CacheMemoryContext, numSupport * sizeof(RegProcedure)); else opcentry->supportProcs = NULL; } else { Assert(numSupport == opcentry->numSupport); } /* * When testing for cache-flush hazards, we intentionally disable the * operator class cache and force reloading of the info on each call. This * is helpful because we want to test the case where a cache flush occurs * while we are loading the info, and it's very hard to provoke that if * this happens only once per opclass per backend. */ #if defined(CLOBBER_CACHE_ALWAYS) opcentry->valid = false; #endif if (opcentry->valid) return opcentry; /* * Need to fill in new entry. * * To avoid infinite recursion during startup, force heap scans if we're * looking up info for the opclasses used by the indexes we would like to * reference here. */ indexOK = criticalRelcachesBuilt || (operatorClassOid != OID_BTREE_OPS_OID && operatorClassOid != INT2_BTREE_OPS_OID); /* * We have to fetch the pg_opclass row to determine its opfamily and * opcintype, which are needed to look up related operators and functions. * It'd be convenient to use the syscache here, but that probably doesn't * work while bootstrapping. */ ScanKeyInit(&skey[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(operatorClassOid)); rel = heap_open(OperatorClassRelationId, AccessShareLock); scan = systable_beginscan(rel, OpclassOidIndexId, indexOK, SnapshotNow, 1, skey); if (HeapTupleIsValid(htup = systable_getnext(scan))) { Form_pg_opclass opclassform = (Form_pg_opclass) GETSTRUCT(htup); opcentry->opcfamily = opclassform->opcfamily; opcentry->opcintype = opclassform->opcintype; } else elog(ERROR, "could not find tuple for opclass %u", operatorClassOid); systable_endscan(scan); heap_close(rel, AccessShareLock); /* * Scan pg_amproc to obtain support procs for the opclass. We only fetch * the default ones (those with lefttype = righttype = opcintype). */ if (numSupport > 0) { ScanKeyInit(&skey[0], Anum_pg_amproc_amprocfamily, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(opcentry->opcfamily)); ScanKeyInit(&skey[1], Anum_pg_amproc_amproclefttype, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(opcentry->opcintype)); ScanKeyInit(&skey[2], Anum_pg_amproc_amprocrighttype, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(opcentry->opcintype)); rel = heap_open(AccessMethodProcedureRelationId, AccessShareLock); scan = systable_beginscan(rel, AccessMethodProcedureIndexId, indexOK, SnapshotNow, 3, skey); while (HeapTupleIsValid(htup = systable_getnext(scan))) { Form_pg_amproc amprocform = (Form_pg_amproc) GETSTRUCT(htup); if (amprocform->amprocnum <= 0 || (StrategyNumber) amprocform->amprocnum > numSupport) elog(ERROR, "invalid amproc number %d for opclass %u", amprocform->amprocnum, operatorClassOid); opcentry->supportProcs[amprocform->amprocnum - 1] = amprocform->amproc; } systable_endscan(scan); heap_close(rel, AccessShareLock); } opcentry->valid = true; return opcentry; }
Definition at line 831 of file relcache.c.
References AllocateRelationDesc(), Assert, elog, ERROR, GETSTRUCT, GetTempNamespaceBackendId(), heap_freetuple(), heap_is_matview_init_state(), HeapTupleGetOid, HeapTupleIsValid, InvalidBackendId, isTempOrToastNamespace(), MyBackendId, OidIsValid, 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_rules, RelationData::rd_rulescxt, RelationData::rd_smgr, RelationBuildRuleLock(), RelationBuildTriggers(), RelationBuildTupleDesc(), RelationCacheInsert, RelationGetRelid, RelationInitIndexAccessInfo(), RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationParseRelOptions(), RELKIND_MATVIEW, RELPERSISTENCE_PERMANENT, RELPERSISTENCE_TEMP, RELPERSISTENCE_UNLOGGED, ScanPgRelation(), and RelationData::trigdesc.
Referenced by load_critical_index(), RelationClearRelation(), and RelationIdGetRelation().
{ Relation relation; Oid relid; HeapTuple pg_class_tuple; Form_pg_class relp; /* * find the tuple in pg_class corresponding to the given relation id */ pg_class_tuple = ScanPgRelation(targetRelId, true); /* * if no such tuple exists, return NULL */ if (!HeapTupleIsValid(pg_class_tuple)) return NULL; /* * get information from the pg_class_tuple */ relid = HeapTupleGetOid(pg_class_tuple); relp = (Form_pg_class) GETSTRUCT(pg_class_tuple); Assert(relid == targetRelId); /* * allocate storage for the relation descriptor, and copy pg_class_tuple * to relation->rd_rel. */ relation = AllocateRelationDesc(relp); /* * initialize the relation's relation id (relation->rd_id) */ RelationGetRelid(relation) = relid; /* * normal relations are not nailed into the cache; nor can a pre-existing * relation be new. It could be temp though. (Actually, it could be new * too, but it's okay to forget that fact if forced to flush the entry.) */ relation->rd_refcnt = 0; relation->rd_isnailed = false; relation->rd_createSubid = InvalidSubTransactionId; relation->rd_newRelfilenodeSubid = InvalidSubTransactionId; switch (relation->rd_rel->relpersistence) { case RELPERSISTENCE_UNLOGGED: case RELPERSISTENCE_PERMANENT: relation->rd_backend = InvalidBackendId; relation->rd_islocaltemp = false; break; case RELPERSISTENCE_TEMP: if (isTempOrToastNamespace(relation->rd_rel->relnamespace)) { relation->rd_backend = MyBackendId; relation->rd_islocaltemp = true; } else { /* * If it's a temp table, but not one of ours, we have to use * the slow, grotty method to figure out the owning backend. * * Note: it's possible that rd_backend gets set to MyBackendId * here, in case we are looking at a pg_class entry left over * from a crashed backend that coincidentally had the same * BackendId we're using. We should *not* consider such a * table to be "ours"; this is why we need the separate * rd_islocaltemp flag. The pg_class entry will get flushed * if/when we clean out the corresponding temp table namespace * in preparation for using it. */ relation->rd_backend = GetTempNamespaceBackendId(relation->rd_rel->relnamespace); Assert(relation->rd_backend != InvalidBackendId); relation->rd_islocaltemp = false; } break; default: elog(ERROR, "invalid relpersistence: %c", relation->rd_rel->relpersistence); break; } /* * initialize the tuple descriptor (relation->rd_att). */ RelationBuildTupleDesc(relation); /* * Fetch rules and triggers that affect this relation */ if (relation->rd_rel->relhasrules) RelationBuildRuleLock(relation); else { relation->rd_rules = NULL; relation->rd_rulescxt = NULL; } if (relation->rd_rel->relhastriggers) RelationBuildTriggers(relation); else relation->trigdesc = NULL; /* * if it's an index, initialize index-related information */ if (OidIsValid(relation->rd_rel->relam)) RelationInitIndexAccessInfo(relation); /* extract reloptions if any */ RelationParseRelOptions(relation, pg_class_tuple); /* * initialize the relation lock manager information */ RelationInitLockInfo(relation); /* see lmgr.c */ /* * initialize physical addressing information for the relation */ RelationInitPhysicalAddr(relation); /* make sure relation is marked as having no open file yet */ relation->rd_smgr = NULL; if (relation->rd_rel->relkind == RELKIND_MATVIEW && heap_is_matview_init_state(relation)) relation->rd_ispopulated = false; else relation->rd_ispopulated = true; /* * now we can free the memory allocated for pg_class_tuple */ heap_freetuple(pg_class_tuple); /* * Insert newly created relation into relcache hash table, if requested. */ if (insertIt) RelationCacheInsert(relation); /* It's fully valid */ relation->rd_isvalid = true; return relation; }
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; }
static void RelationBuildRuleLock | ( | Relation | relation | ) | [static] |
Definition at line 613 of file relcache.c.
References AccessShareLock, RewriteRule::actions, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE, ALLOCSET_SMALL_MINSIZE, AllocSetContextCreate(), Anum_pg_rewrite_ev_action, Anum_pg_rewrite_ev_class, Anum_pg_rewrite_ev_qual, Assert, RewriteRule::attrno, BTEqualStrategyNumber, CacheMemoryContext, RewriteRule::enabled, RewriteRule::event, GETSTRUCT, heap_close, heap_getattr, heap_open(), HeapTupleGetOid, HeapTupleIsValid, RewriteRule::isInstead, MemoryContextAlloc(), MemoryContextDelete(), MemoryContextSwitchTo(), RuleLock::numLocks, ObjectIdGetDatum, pfree(), RewriteRule::qual, RelationData::rd_rel, RelationData::rd_rules, RelationData::rd_rulescxt, RelationGetDescr, RelationGetRelationName, RelationGetRelid, repalloc(), RewriteRelationId, RewriteRelRulenameIndexId, RewriteRule::ruleId, RuleLock::rules, rules, ScanKeyInit(), setRuleCheckAsUser(), SnapshotNow, stringToNode(), systable_beginscan(), systable_endscan(), systable_getnext(), and TextDatumGetCString.
Referenced by RelationBuildDesc(), and RelationCacheInitializePhase3().
{ MemoryContext rulescxt; MemoryContext oldcxt; HeapTuple rewrite_tuple; Relation rewrite_desc; TupleDesc rewrite_tupdesc; SysScanDesc rewrite_scan; ScanKeyData key; RuleLock *rulelock; int numlocks; RewriteRule **rules; int maxlocks; /* * Make the private context. Parameters are set on the assumption that * it'll probably not contain much data. */ rulescxt = AllocSetContextCreate(CacheMemoryContext, RelationGetRelationName(relation), ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE); relation->rd_rulescxt = rulescxt; /* * allocate an array to hold the rewrite rules (the array is extended if * necessary) */ maxlocks = 4; rules = (RewriteRule **) MemoryContextAlloc(rulescxt, sizeof(RewriteRule *) * maxlocks); numlocks = 0; /* * form a scan key */ ScanKeyInit(&key, Anum_pg_rewrite_ev_class, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(relation))); /* * open pg_rewrite and begin a scan * * Note: since we scan the rules using RewriteRelRulenameIndexId, we will * be reading the rules in name order, except possibly during * emergency-recovery operations (ie, IgnoreSystemIndexes). This in turn * ensures that rules will be fired in name order. */ rewrite_desc = heap_open(RewriteRelationId, AccessShareLock); rewrite_tupdesc = RelationGetDescr(rewrite_desc); rewrite_scan = systable_beginscan(rewrite_desc, RewriteRelRulenameIndexId, true, SnapshotNow, 1, &key); while (HeapTupleIsValid(rewrite_tuple = systable_getnext(rewrite_scan))) { Form_pg_rewrite rewrite_form = (Form_pg_rewrite) GETSTRUCT(rewrite_tuple); bool isnull; Datum rule_datum; char *rule_str; RewriteRule *rule; rule = (RewriteRule *) MemoryContextAlloc(rulescxt, sizeof(RewriteRule)); rule->ruleId = HeapTupleGetOid(rewrite_tuple); rule->event = rewrite_form->ev_type - '0'; rule->attrno = rewrite_form->ev_attr; rule->enabled = rewrite_form->ev_enabled; rule->isInstead = rewrite_form->is_instead; /* * Must use heap_getattr to fetch ev_action and ev_qual. Also, the * rule strings are often large enough to be toasted. To avoid * leaking memory in the caller's context, do the detoasting here so * we can free the detoasted version. */ rule_datum = heap_getattr(rewrite_tuple, Anum_pg_rewrite_ev_action, rewrite_tupdesc, &isnull); Assert(!isnull); rule_str = TextDatumGetCString(rule_datum); oldcxt = MemoryContextSwitchTo(rulescxt); rule->actions = (List *) stringToNode(rule_str); MemoryContextSwitchTo(oldcxt); pfree(rule_str); rule_datum = heap_getattr(rewrite_tuple, Anum_pg_rewrite_ev_qual, rewrite_tupdesc, &isnull); Assert(!isnull); rule_str = TextDatumGetCString(rule_datum); oldcxt = MemoryContextSwitchTo(rulescxt); rule->qual = (Node *) stringToNode(rule_str); MemoryContextSwitchTo(oldcxt); pfree(rule_str); /* * We want the rule's table references to be checked as though by the * table owner, not the user referencing the rule. Therefore, scan * through the rule's actions and set the checkAsUser field on all * rtable entries. We have to look at the qual as well, in case it * contains sublinks. * * The reason for doing this when the rule is loaded, rather than when * it is stored, is that otherwise ALTER TABLE OWNER would have to * grovel through stored rules to update checkAsUser fields. Scanning * the rule tree during load is relatively cheap (compared to * constructing it in the first place), so we do it here. */ setRuleCheckAsUser((Node *) rule->actions, relation->rd_rel->relowner); setRuleCheckAsUser(rule->qual, relation->rd_rel->relowner); if (numlocks >= maxlocks) { maxlocks *= 2; rules = (RewriteRule **) repalloc(rules, sizeof(RewriteRule *) * maxlocks); } rules[numlocks++] = rule; } /* * end the scan and close the attribute relation */ systable_endscan(rewrite_scan); heap_close(rewrite_desc, AccessShareLock); /* * there might not be any rules (if relhasrules is out-of-date) */ if (numlocks == 0) { relation->rd_rules = NULL; relation->rd_rulescxt = NULL; MemoryContextDelete(rulescxt); return; } /* * form a RuleLock and insert into relation */ rulelock = (RuleLock *) MemoryContextAlloc(rulescxt, sizeof(RuleLock)); rulelock->numLocks = numlocks; rulelock->rules = rules; relation->rd_rules = rulelock; }
static void RelationBuildTupleDesc | ( | Relation | relation | ) | [static] |
Definition at line 441 of file relcache.c.
References AccessShareLock, attrDefault::adbin, attrDefault::adnum, Anum_pg_attribute_attnum, Anum_pg_attribute_attrelid, Assert, AttrDefaultFetch(), ATTRIBUTE_FIXED_PART_SIZE, AttributeRelationId, AttributeRelidNumIndexId, tupleDesc::attrs, BTEqualStrategyNumber, BTGreaterStrategyNumber, CacheMemoryContext, tupleConstr::check, CheckConstraintFetch(), tupleDesc::constr, criticalRelcachesBuilt, tupleConstr::defval, elog, ERROR, GETSTRUCT, tupleConstr::has_not_null, heap_close, heap_open(), HeapTupleIsValid, i, Int16GetDatum, MemoryContextAlloc(), MemoryContextAllocZero(), NULL, tupleConstr::num_check, tupleConstr::num_defval, ObjectIdGetDatum, pfree(), RelationData::rd_att, RelationData::rd_rel, RelationGetRelationName, RelationGetRelid, repalloc(), ScanKeyInit(), SnapshotNow, systable_beginscan(), systable_endscan(), systable_getnext(), tupleDesc::tdhasoid, tupleDesc::tdtypeid, and tupleDesc::tdtypmod.
Referenced by RelationBuildDesc().
{ HeapTuple pg_attribute_tuple; Relation pg_attribute_desc; SysScanDesc pg_attribute_scan; ScanKeyData skey[2]; int need; TupleConstr *constr; AttrDefault *attrdef = NULL; int ndef = 0; /* copy some fields from pg_class row to rd_att */ relation->rd_att->tdtypeid = relation->rd_rel->reltype; relation->rd_att->tdtypmod = -1; /* unnecessary, but... */ relation->rd_att->tdhasoid = relation->rd_rel->relhasoids; constr = (TupleConstr *) MemoryContextAlloc(CacheMemoryContext, sizeof(TupleConstr)); constr->has_not_null = false; /* * Form a scan key that selects only user attributes (attnum > 0). * (Eliminating system attribute rows at the index level is lots faster * than fetching them.) */ ScanKeyInit(&skey[0], Anum_pg_attribute_attrelid, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(relation))); ScanKeyInit(&skey[1], Anum_pg_attribute_attnum, BTGreaterStrategyNumber, F_INT2GT, Int16GetDatum(0)); /* * Open pg_attribute and begin a scan. Force heap scan if we haven't yet * built the critical relcache entries (this includes initdb and startup * without a pg_internal.init file). */ pg_attribute_desc = heap_open(AttributeRelationId, AccessShareLock); pg_attribute_scan = systable_beginscan(pg_attribute_desc, AttributeRelidNumIndexId, criticalRelcachesBuilt, SnapshotNow, 2, skey); /* * add attribute data to relation->rd_att */ need = relation->rd_rel->relnatts; while (HeapTupleIsValid(pg_attribute_tuple = systable_getnext(pg_attribute_scan))) { Form_pg_attribute attp; attp = (Form_pg_attribute) GETSTRUCT(pg_attribute_tuple); if (attp->attnum <= 0 || attp->attnum > relation->rd_rel->relnatts) elog(ERROR, "invalid attribute number %d for %s", attp->attnum, RelationGetRelationName(relation)); memcpy(relation->rd_att->attrs[attp->attnum - 1], attp, ATTRIBUTE_FIXED_PART_SIZE); /* Update constraint/default info */ if (attp->attnotnull) constr->has_not_null = true; if (attp->atthasdef) { if (attrdef == NULL) attrdef = (AttrDefault *) MemoryContextAllocZero(CacheMemoryContext, relation->rd_rel->relnatts * sizeof(AttrDefault)); attrdef[ndef].adnum = attp->attnum; attrdef[ndef].adbin = NULL; ndef++; } need--; if (need == 0) break; } /* * end the scan and close the attribute relation */ systable_endscan(pg_attribute_scan); heap_close(pg_attribute_desc, AccessShareLock); if (need != 0) elog(ERROR, "catalog is missing %d attribute(s) for relid %u", need, RelationGetRelid(relation)); /* * The attcacheoff values we read from pg_attribute should all be -1 * ("unknown"). Verify this if assert checking is on. They will be * computed when and if needed during tuple access. */ #ifdef USE_ASSERT_CHECKING { int i; for (i = 0; i < relation->rd_rel->relnatts; i++) Assert(relation->rd_att->attrs[i]->attcacheoff == -1); } #endif /* * However, we can easily set the attcacheoff value for the first * attribute: it must be zero. This eliminates the need for special cases * for attnum=1 that used to exist in fastgetattr() and index_getattr(). */ if (relation->rd_rel->relnatts > 0) relation->rd_att->attrs[0]->attcacheoff = 0; /* * Set up constraint/default info */ if (constr->has_not_null || ndef > 0 || relation->rd_rel->relchecks) { relation->rd_att->constr = constr; if (ndef > 0) /* DEFAULTs */ { if (ndef < relation->rd_rel->relnatts) constr->defval = (AttrDefault *) repalloc(attrdef, ndef * sizeof(AttrDefault)); else constr->defval = attrdef; constr->num_defval = ndef; AttrDefaultFetch(relation); } else constr->num_defval = 0; if (relation->rd_rel->relchecks > 0) /* CHECKs */ { constr->num_check = relation->rd_rel->relchecks; constr->check = (ConstrCheck *) MemoryContextAllocZero(CacheMemoryContext, constr->num_check * sizeof(ConstrCheck)); CheckConstraintFetch(relation); } else constr->num_check = 0; } else { pfree(constr); relation->rd_att->constr = NULL; } }
void RelationCacheInitFilePostInvalidate | ( | void | ) |
Definition at line 4780 of file relcache.c.
References LWLockRelease(), and RelCacheInitLock.
Referenced by AtEOXact_Inval(), FinishPreparedTransaction(), and ProcessCommittedInvalidationMessages().
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); }
static void RelationCacheInitFileRemoveInDir | ( | const char * | tblspcpath | ) | [static] |
Definition at line 4838 of file relcache.c.
References AllocateDir(), dirent::d_name, elog, FreeDir(), LOG, NULL, ReadDir(), RELCACHE_INIT_FILENAME, snprintf(), and unlink_initfile().
Referenced by RelationCacheInitFileRemove().
{ DIR *dir; struct dirent *de; char initfilename[MAXPGPATH]; /* Scan the tablespace directory to find per-database directories */ dir = AllocateDir(tblspcpath); if (dir == NULL) { elog(LOG, "could not open tablespace directory \"%s\": %m", tblspcpath); return; } while ((de = ReadDir(dir, tblspcpath)) != NULL) { if (strspn(de->d_name, "0123456789") == strlen(de->d_name)) { /* Try to remove the init file in each database */ snprintf(initfilename, sizeof(initfilename), "%s/%s/%s", tblspcpath, de->d_name, RELCACHE_INIT_FILENAME); unlink_initfile(initfilename); } } 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 | ) |
Definition at line 2138 of file relcache.c.
References PointerIsValid, RelationFlushRelation(), RelationIdCacheLookup, and relcacheInvalsReceived.
Referenced by ExecRefreshMatView(), LocalExecuteInvalidationMessage(), and SetMatViewToPopulated().
{ Relation relation; RelationIdCacheLookup(relationId, relation); if (PointerIsValid(relation)) { relcacheInvalsReceived++; RelationFlushRelation(relation); } }
Definition at line 1874 of file relcache.c.
References Assert, CLASS_TUPLE_SIZE, elog, equalRuleLocks(), equalTupleDescs(), ERROR, heap_is_matview_init_state(), NULL, RelationData::rd_att, RelationData::rd_indexcxt, RelationData::rd_isnailed, RelationData::rd_ispopulated, RelationData::rd_isvalid, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_rules, RelationBuildDesc(), RelationCacheDelete, RelationCloseSmgr, RelationDestroyRelation(), RelationGetRelid, RelationHasReferenceCountZero, RelationInitPhysicalAddr(), RelationReloadIndexInfo(), RELKIND_INDEX, RELKIND_MATVIEW, and SWAPFIELD.
Referenced by AtEOSubXact_cleanup(), AtEOXact_cleanup(), RelationCacheInvalidate(), RelationClose(), RelationFlushRelation(), RelationForgetRelation(), and RelationIdGetRelation().
{ /* * As per notes above, a rel to be rebuilt MUST have refcnt > 0; while of * course it would be a bad idea to blow away one with nonzero refcnt. */ Assert(rebuild ? !RelationHasReferenceCountZero(relation) : RelationHasReferenceCountZero(relation)); /* * Make sure smgr and lower levels close the relation's files, if they * weren't closed already. If the relation is not getting deleted, the * next smgr access should reopen the files automatically. This ensures * that the low-level file access state is updated after, say, a vacuum * truncation. */ RelationCloseSmgr(relation); /* * Never, never ever blow away a nailed-in system relation, because we'd * be unable to recover. However, we must redo RelationInitPhysicalAddr * in case it is a mapped relation whose mapping changed. * * If it's a nailed index, then we need to re-read the pg_class row to see * if its relfilenode changed. We can't necessarily do that here, because * we might be in a failed transaction. We assume it's okay to do it if * there are open references to the relcache entry (cf notes for * AtEOXact_RelationCache). Otherwise just mark the entry as possibly * invalid, and it'll be fixed when next opened. */ if (relation->rd_isnailed) { RelationInitPhysicalAddr(relation); if (relation->rd_rel->relkind == RELKIND_MATVIEW && heap_is_matview_init_state(relation)) relation->rd_ispopulated = false; else relation->rd_ispopulated = true; if (relation->rd_rel->relkind == RELKIND_INDEX) { relation->rd_isvalid = false; /* needs to be revalidated */ if (relation->rd_refcnt > 1) RelationReloadIndexInfo(relation); } return; } /* * Even non-system indexes should not be blown away if they are open and * have valid index support information. This avoids problems with active * use of the index support information. As with nailed indexes, we * re-read the pg_class row to handle possible physical relocation of the * index, and we check for pg_index updates too. */ if (relation->rd_rel->relkind == RELKIND_INDEX && relation->rd_refcnt > 0 && relation->rd_indexcxt != NULL) { relation->rd_isvalid = false; /* needs to be revalidated */ RelationReloadIndexInfo(relation); return; } /* Mark it invalid until we've finished rebuild */ relation->rd_isvalid = false; /* * If we're really done with the relcache entry, blow it away. But if * someone is still using it, reconstruct the whole deal without moving * the physical RelationData record (so that the someone's pointer is * still valid). */ if (!rebuild) { /* Remove it from the hash table */ RelationCacheDelete(relation); /* And release storage */ RelationDestroyRelation(relation); } else { /* * Our strategy for rebuilding an open relcache entry is to build a * new entry from scratch, swap its contents with the old entry, and * finally delete the new entry (along with any infrastructure swapped * over from the old entry). This is to avoid trouble in case an * error causes us to lose control partway through. The old entry * will still be marked !rd_isvalid, so we'll try to rebuild it again * on next access. Meanwhile it's not any less valid than it was * before, so any code that might expect to continue accessing it * isn't hurt by the rebuild failure. (Consider for example a * subtransaction that ALTERs a table and then gets canceled partway * through the cache entry rebuild. The outer transaction should * still see the not-modified cache entry as valid.) The worst * consequence of an error is leaking the necessarily-unreferenced new * entry, and this shouldn't happen often enough for that to be a big * problem. * * When rebuilding an open relcache entry, we must preserve ref count, * rd_createSubid/rd_newRelfilenodeSubid, and rd_toastoid state. Also * attempt to preserve the pg_class entry (rd_rel), tupledesc, and * rewrite-rule substructures in place, because various places assume * that these structures won't move while they are working with an * open relcache entry. (Note: the refcount mechanism for tupledescs * might someday allow us to remove this hack for the tupledesc.) * * Note that this process does not touch CurrentResourceOwner; which * is good because whatever ref counts the entry may have do not * necessarily belong to that resource owner. */ Relation newrel; Oid save_relid = RelationGetRelid(relation); bool keep_tupdesc; bool keep_rules; /* Build temporary entry, but don't link it into hashtable */ newrel = RelationBuildDesc(save_relid, false); if (newrel == NULL) { /* Should only get here if relation was deleted */ RelationCacheDelete(relation); RelationDestroyRelation(relation); elog(ERROR, "relation %u deleted while still in use", save_relid); } keep_tupdesc = equalTupleDescs(relation->rd_att, newrel->rd_att); keep_rules = equalRuleLocks(relation->rd_rules, newrel->rd_rules); /* * Perform swapping of the relcache entry contents. Within this * process the old entry is momentarily invalid, so there *must* be no * possibility of CHECK_FOR_INTERRUPTS within this sequence. Do it in * all-in-line code for safety. * * Since the vast majority of fields should be swapped, our method is * to swap the whole structures and then re-swap those few fields we * didn't want swapped. */ #define SWAPFIELD(fldtype, fldname) \ do { \ fldtype _tmp = newrel->fldname; \ newrel->fldname = relation->fldname; \ relation->fldname = _tmp; \ } while (0) /* swap all Relation struct fields */ { RelationData tmpstruct; memcpy(&tmpstruct, newrel, sizeof(RelationData)); memcpy(newrel, relation, sizeof(RelationData)); memcpy(relation, &tmpstruct, sizeof(RelationData)); } /* rd_smgr must not be swapped, due to back-links from smgr level */ SWAPFIELD(SMgrRelation, rd_smgr); /* rd_refcnt must be preserved */ SWAPFIELD(int, rd_refcnt); /* isnailed shouldn't change */ Assert(newrel->rd_isnailed == relation->rd_isnailed); /* creation sub-XIDs must be preserved */ SWAPFIELD(SubTransactionId, rd_createSubid); SWAPFIELD(SubTransactionId, rd_newRelfilenodeSubid); /* un-swap rd_rel pointers, swap contents instead */ SWAPFIELD(Form_pg_class, rd_rel); /* ... but actually, we don't have to update newrel->rd_rel */ memcpy(relation->rd_rel, newrel->rd_rel, CLASS_TUPLE_SIZE); /* preserve old tupledesc and rules if no logical change */ if (keep_tupdesc) SWAPFIELD(TupleDesc, rd_att); if (keep_rules) { SWAPFIELD(RuleLock *, rd_rules); SWAPFIELD(MemoryContext, rd_rulescxt); } /* toast OID override must be preserved */ SWAPFIELD(Oid, rd_toastoid); /* pgstat_info must be preserved */ SWAPFIELD(struct PgStat_TableStatus *, pgstat_info); #undef SWAPFIELD /* And now we can throw away the temporary entry */ RelationDestroyRelation(newrel); } }
void RelationClose | ( | Relation | relation | ) |
Definition at line 1667 of file relcache.c.
References InvalidSubTransactionId, RelationData::rd_createSubid, RelationData::rd_newRelfilenodeSubid, RelationClearRelation(), RelationDecrementReferenceCount(), and RelationHasReferenceCountZero.
Referenced by index_close(), relation_close(), and ResourceOwnerReleaseInternal().
{ /* Note: no locking manipulations needed */ RelationDecrementReferenceCount(relation); #ifdef RELCACHE_FORCE_RELEASE if (RelationHasReferenceCountZero(relation) && relation->rd_createSubid == InvalidSubTransactionId && relation->rd_newRelfilenodeSubid == InvalidSubTransactionId) RelationClearRelation(relation, false); #endif }
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 RelationDecrementReferenceCount | ( | Relation | rel | ) |
Definition at line 1647 of file relcache.c.
References Assert, CurrentResourceOwner, IsBootstrapProcessingMode, RelationData::rd_refcnt, and ResourceOwnerForgetRelationRef().
Referenced by heap_endscan(), index_endscan(), RelationCacheInitializePhase3(), RelationClose(), and RelationFlushRelation().
{ Assert(rel->rd_refcnt > 0); rel->rd_refcnt -= 1; if (!IsBootstrapProcessingMode()) ResourceOwnerForgetRelationRef(CurrentResourceOwner, rel); }
static void RelationDestroyRelation | ( | Relation | relation | ) | [static] |
Definition at line 1815 of file relcache.c.
References Assert, bms_free(), FreeTriggerDesc(), FreeTupleDesc(), list_free(), MemoryContextDelete(), pfree(), RelationData::rd_am, RelationData::rd_att, RelationData::rd_fdwroutine, RelationData::rd_indexattr, RelationData::rd_indexcxt, RelationData::rd_indexlist, RelationData::rd_indextuple, RelationData::rd_options, RelationData::rd_rel, RelationData::rd_rulescxt, RelationCloseSmgr, RelationHasReferenceCountZero, tupleDesc::tdrefcount, and RelationData::trigdesc.
Referenced by RelationClearRelation().
{ Assert(RelationHasReferenceCountZero(relation)); /* * Make sure smgr and lower levels close the relation's files, if they * weren't closed already. (This was probably done by caller, but let's * just be real sure.) */ RelationCloseSmgr(relation); /* * Free all the subsidiary data structures of the relcache entry, then the * entry itself. */ if (relation->rd_rel) pfree(relation->rd_rel); /* can't use DecrTupleDescRefCount here */ Assert(relation->rd_att->tdrefcount > 0); if (--relation->rd_att->tdrefcount == 0) FreeTupleDesc(relation->rd_att); list_free(relation->rd_indexlist); bms_free(relation->rd_indexattr); FreeTriggerDesc(relation->trigdesc); if (relation->rd_options) pfree(relation->rd_options); if (relation->rd_indextuple) pfree(relation->rd_indextuple); if (relation->rd_am) pfree(relation->rd_am); if (relation->rd_indexcxt) MemoryContextDelete(relation->rd_indexcxt); if (relation->rd_rulescxt) MemoryContextDelete(relation->rd_rulescxt); if (relation->rd_fdwroutine) pfree(relation->rd_fdwroutine); pfree(relation); }
static void RelationFlushRelation | ( | Relation | relation | ) | [static] |
Definition at line 2070 of file relcache.c.
References InvalidSubTransactionId, RelationData::rd_createSubid, RelationData::rd_newRelfilenodeSubid, RelationClearRelation(), RelationDecrementReferenceCount(), RelationHasReferenceCountZero, and RelationIncrementReferenceCount().
Referenced by RelationCacheInvalidateEntry().
{ if (relation->rd_createSubid != InvalidSubTransactionId || relation->rd_newRelfilenodeSubid != InvalidSubTransactionId) { /* * New relcache entries are always rebuilt, not flushed; else we'd * forget the "new" status of the relation, which is a useful * optimization to have. Ditto for the new-relfilenode status. * * The rel could have zero refcnt here, so temporarily increment the * refcnt to ensure it's safe to rebuild it. We can assume that the * current transaction has some lock on the rel already. */ RelationIncrementReferenceCount(relation); RelationClearRelation(relation, true); RelationDecrementReferenceCount(relation); } else { /* * Pre-existing rels can be dropped from the relcache if not open. */ bool rebuild = !RelationHasReferenceCountZero(relation); RelationClearRelation(relation, rebuild); } }
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); }
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; }
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; }
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; }
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; }
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; }
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; }
Definition at line 4719 of file relcache.c.
References list_member_oid().
Referenced by RegisterRelcacheInvalidation().
{ return list_member_oid(initFileRelationIds, relationId); }
void RelationIncrementReferenceCount | ( | Relation | rel | ) |
Definition at line 1634 of file relcache.c.
References CurrentResourceOwner, IsBootstrapProcessingMode, RelationData::rd_refcnt, ResourceOwnerEnlargeRelationRefs(), and ResourceOwnerRememberRelationRef().
Referenced by heap_beginscan_internal(), index_beginscan_internal(), RelationBuildLocalRelation(), RelationCacheInitializePhase3(), RelationFlushRelation(), and RelationIdGetRelation().
{ ResourceOwnerEnlargeRelationRefs(CurrentResourceOwner); rel->rd_refcnt += 1; if (!IsBootstrapProcessingMode()) ResourceOwnerRememberRelationRef(CurrentResourceOwner, rel); }
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; }
static void RelationInitPhysicalAddr | ( | Relation | relation | ) | [static] |
Definition at line 990 of file relcache.c.
References RelFileNode::dbNode, elog, ERROR, GLOBALTABLESPACE_OID, MyDatabaseId, MyDatabaseTableSpace, OidIsValid, RelationData::rd_id, RelationData::rd_node, RelationData::rd_rel, RelationGetRelationName, RelationMapOidToFilenode(), RelFileNode::relNode, and RelFileNode::spcNode.
Referenced by formrdesc(), load_relcache_init_file(), RelationBuildDesc(), RelationBuildLocalRelation(), RelationCacheInvalidate(), RelationClearRelation(), and RelationReloadIndexInfo().
{ if (relation->rd_rel->reltablespace) relation->rd_node.spcNode = relation->rd_rel->reltablespace; else relation->rd_node.spcNode = MyDatabaseTableSpace; if (relation->rd_node.spcNode == GLOBALTABLESPACE_OID) relation->rd_node.dbNode = InvalidOid; else relation->rd_node.dbNode = MyDatabaseId; if (relation->rd_rel->relfilenode) relation->rd_node.relNode = relation->rd_rel->relfilenode; else { /* Consult the relation mapper */ relation->rd_node.relNode = RelationMapOidToFilenode(relation->rd_id, relation->rd_rel->relisshared); if (!OidIsValid(relation->rd_node.relNode)) elog(ERROR, "could not find relation mapping for relation \"%s\", OID %u", RelationGetRelationName(relation), relation->rd_id); } }
Definition at line 390 of file relcache.c.
References CacheMemoryContext, extractRelOptions(), GetPgClassDescriptor(), InvalidOid, MemoryContextAlloc(), pfree(), RelationData::rd_am, RelationData::rd_options, RelationData::rd_rel, RELKIND_INDEX, RELKIND_MATVIEW, RELKIND_RELATION, RELKIND_TOASTVALUE, RELKIND_VIEW, and VARSIZE.
Referenced by RelationBuildDesc(), RelationCacheInitializePhase3(), and RelationReloadIndexInfo().
{ bytea *options; relation->rd_options = NULL; /* Fall out if relkind should not have options */ switch (relation->rd_rel->relkind) { case RELKIND_RELATION: case RELKIND_TOASTVALUE: case RELKIND_INDEX: case RELKIND_VIEW: case RELKIND_MATVIEW: break; default: return; } /* * Fetch reloptions from tuple; have to use a hardwired descriptor because * we might not have any other for pg_class yet (consider executing this * code for pg_class itself) */ options = extractRelOptions(tuple, GetPgClassDescriptor(), relation->rd_rel->relkind == RELKIND_INDEX ? relation->rd_am->amoptions : InvalidOid); /* * Copy parsed data into CacheMemoryContext. To guard against the * possibility of leaks in the reloptions code, we want to do the actual * parsing in the caller's memory context and copy the results into * CacheMemoryContext after the fact. */ if (options) { relation->rd_options = MemoryContextAlloc(CacheMemoryContext, VARSIZE(options)); memcpy(relation->rd_options, options, VARSIZE(options)); pfree(options); } }
static void RelationReloadIndexInfo | ( | Relation | relation | ) | [static] |
Definition at line 1708 of file relcache.c.
References Assert, CLASS_TUPLE_SIZE, criticalRelcachesBuilt, elog, ERROR, GETSTRUCT, heap_freetuple(), HeapTupleHeaderGetXmin, HeapTupleHeaderSetXmin, HeapTupleIsValid, INDEXRELID, IsSystemRelation(), NULL, ObjectIdGetDatum, pfree(), RelationData::rd_amcache, RelationData::rd_index, RelationData::rd_indextuple, RelationData::rd_ispopulated, RelationData::rd_isvalid, RelationData::rd_options, RelationData::rd_rel, RelationData::rd_smgr, RelationGetRelid, RelationInitPhysicalAddr(), RelationParseRelOptions(), ReleaseSysCache(), RELKIND_INDEX, ScanPgRelation(), SearchSysCache1, and HeapTupleData::t_data.
Referenced by RelationClearRelation(), and RelationIdGetRelation().
{ bool indexOK; HeapTuple pg_class_tuple; Form_pg_class relp; /* Should be called only for invalidated indexes */ Assert(relation->rd_rel->relkind == RELKIND_INDEX && !relation->rd_isvalid); /* Should be closed at smgr level */ Assert(relation->rd_smgr == NULL); /* Must free any AM cached data upon relcache flush */ if (relation->rd_amcache) pfree(relation->rd_amcache); relation->rd_amcache = NULL; /* * If it's a shared index, we might be called before backend startup has * finished selecting a database, in which case we have no way to read * pg_class yet. However, a shared index can never have any significant * schema updates, so it's okay to ignore the invalidation signal. Just * mark it valid and return without doing anything more. */ if (relation->rd_rel->relisshared && !criticalRelcachesBuilt) { relation->rd_isvalid = true; return; } /* * Read the pg_class row * * Don't try to use an indexscan of pg_class_oid_index to reload the info * for pg_class_oid_index ... */ indexOK = (RelationGetRelid(relation) != ClassOidIndexId); pg_class_tuple = ScanPgRelation(RelationGetRelid(relation), indexOK); if (!HeapTupleIsValid(pg_class_tuple)) elog(ERROR, "could not find pg_class tuple for index %u", RelationGetRelid(relation)); relp = (Form_pg_class) GETSTRUCT(pg_class_tuple); memcpy(relation->rd_rel, relp, CLASS_TUPLE_SIZE); /* Reload reloptions in case they changed */ if (relation->rd_options) pfree(relation->rd_options); RelationParseRelOptions(relation, pg_class_tuple); /* done with pg_class tuple */ heap_freetuple(pg_class_tuple); /* We must recalculate physical address in case it changed */ RelationInitPhysicalAddr(relation); relation->rd_ispopulated = true; /* * For a non-system index, there are fields of the pg_index row that are * allowed to change, so re-read that row and update the relcache entry. * Most of the info derived from pg_index (such as support function lookup * info) cannot change, and indeed the whole point of this routine is to * update the relcache entry without clobbering that data; so wholesale * replacement is not appropriate. */ if (!IsSystemRelation(relation)) { HeapTuple tuple; Form_pg_index index; tuple = SearchSysCache1(INDEXRELID, ObjectIdGetDatum(RelationGetRelid(relation))); if (!HeapTupleIsValid(tuple)) elog(ERROR, "cache lookup failed for index %u", RelationGetRelid(relation)); index = (Form_pg_index) GETSTRUCT(tuple); /* * Basically, let's just copy all the bool fields. There are one or * two of these that can't actually change in the current code, but * it's not worth it to track exactly which ones they are. None of * the array fields are allowed to change, though. */ relation->rd_index->indisunique = index->indisunique; relation->rd_index->indisprimary = index->indisprimary; relation->rd_index->indisexclusion = index->indisexclusion; relation->rd_index->indimmediate = index->indimmediate; relation->rd_index->indisclustered = index->indisclustered; relation->rd_index->indisvalid = index->indisvalid; relation->rd_index->indcheckxmin = index->indcheckxmin; relation->rd_index->indisready = index->indisready; relation->rd_index->indislive = index->indislive; /* Copy xmin too, as that is needed to make sense of indcheckxmin */ HeapTupleHeaderSetXmin(relation->rd_indextuple->t_data, HeapTupleHeaderGetXmin(tuple->t_data)); ReleaseSysCache(tuple); } /* Okay, now it's valid again */ relation->rd_isvalid = true; }
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); }
Definition at line 276 of file relcache.c.
References AccessShareLock, BTEqualStrategyNumber, ClassOidIndexId, criticalRelcachesBuilt, elog, FATAL, heap_close, heap_copytuple(), heap_open(), HeapTupleIsValid, MyDatabaseId, ObjectIdAttributeNumber, ObjectIdGetDatum, OidIsValid, RelationRelationId, ScanKeyInit(), SnapshotNow, systable_beginscan(), systable_endscan(), and systable_getnext().
Referenced by RelationBuildDesc(), and RelationReloadIndexInfo().
{ HeapTuple pg_class_tuple; Relation pg_class_desc; SysScanDesc pg_class_scan; ScanKeyData key[1]; /* * If something goes wrong during backend startup, we might find ourselves * trying to read pg_class before we've selected a database. That ain't * gonna work, so bail out with a useful error message. If this happens, * it probably means a relcache entry that needs to be nailed isn't. */ if (!OidIsValid(MyDatabaseId)) elog(FATAL, "cannot read pg_class without having selected a database"); /* * form a scan key */ ScanKeyInit(&key[0], ObjectIdAttributeNumber, BTEqualStrategyNumber, F_OIDEQ, ObjectIdGetDatum(targetRelId)); /* * Open pg_class and fetch a tuple. Force heap scan if we haven't yet * built the critical relcache entries (this includes initdb and startup * without a pg_internal.init file). The caller can also force a heap * scan by setting indexOK == false. */ pg_class_desc = heap_open(RelationRelationId, AccessShareLock); pg_class_scan = systable_beginscan(pg_class_desc, ClassOidIndexId, indexOK && criticalRelcachesBuilt, SnapshotNow, 1, key); pg_class_tuple = systable_getnext(pg_class_scan); /* * Must copy tuple before releasing buffer. */ if (HeapTupleIsValid(pg_class_tuple)) pg_class_tuple = heap_copytuple(pg_class_tuple); /* all done */ systable_endscan(pg_class_scan); heap_close(pg_class_desc, AccessShareLock); return pg_class_tuple; }
static void unlink_initfile | ( | const char * | initfilename | ) | [static] |
Definition at line 4868 of file relcache.c.
References elog, LOG, and unlink().
Referenced by RelationCacheInitFileRemove(), and RelationCacheInitFileRemoveInDir().
static void write_item | ( | const void * | data, | |
Size | len, | |||
FILE * | fp | |||
) | [static] |
Definition at line 4701 of file relcache.c.
Referenced by write_relcache_init_file().
static void write_relcache_init_file | ( | bool | shared | ) | [static] |
Definition at line 4516 of file relcache.c.
References AcceptInvalidationMessages(), AllocateFile(), ATTRIBUTE_FIXED_PART_SIZE, tupleDesc::attrs, CacheMemoryContext, CLASS_TUPLE_SIZE, DatabasePath, elog, ereport, errcode_for_file_access(), errdetail(), errmsg(), FATAL, FormData_pg_am, FreeFile(), hash_seq_init(), hash_seq_search(), HEAPTUPLESIZE, i, lcons_oid(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MemoryContextSwitchTo(), MyProcPid, NULL, PG_BINARY_W, RelationData::rd_am, RelationData::rd_att, RelationData::rd_indcollation, RelationData::rd_indextuple, RelationData::rd_indoption, RelationData::rd_opcintype, RelationData::rd_opfamily, RelationData::rd_options, RelationData::rd_rel, RelationData::rd_support, RelationGetRelid, RELCACHE_INIT_FILENAME, RelCacheInitLock, relcacheInvalsReceived, relidcacheent::reldesc, RELKIND_INDEX, snprintf(), HeapTupleData::t_len, unlink(), VARSIZE, WARNING, and write_item().
Referenced by RelationCacheInitializePhase3().
{ FILE *fp; char tempfilename[MAXPGPATH]; char finalfilename[MAXPGPATH]; int magic; HASH_SEQ_STATUS status; RelIdCacheEnt *idhentry; MemoryContext oldcxt; int i; /* * We must write a temporary file and rename it into place. Otherwise, * another backend starting at about the same time might crash trying to * read the partially-complete file. */ if (shared) { snprintf(tempfilename, sizeof(tempfilename), "global/%s.%d", RELCACHE_INIT_FILENAME, MyProcPid); snprintf(finalfilename, sizeof(finalfilename), "global/%s", RELCACHE_INIT_FILENAME); } else { snprintf(tempfilename, sizeof(tempfilename), "%s/%s.%d", DatabasePath, RELCACHE_INIT_FILENAME, MyProcPid); snprintf(finalfilename, sizeof(finalfilename), "%s/%s", DatabasePath, RELCACHE_INIT_FILENAME); } unlink(tempfilename); /* in case it exists w/wrong permissions */ fp = AllocateFile(tempfilename, PG_BINARY_W); if (fp == NULL) { /* * We used to consider this a fatal error, but we might as well * continue with backend startup ... */ ereport(WARNING, (errcode_for_file_access(), errmsg("could not create relation-cache initialization file \"%s\": %m", tempfilename), errdetail("Continuing anyway, but there's something wrong."))); return; } /* * Write a magic number to serve as a file version identifier. We can * change the magic number whenever the relcache layout changes. */ magic = RELCACHE_INIT_FILEMAGIC; if (fwrite(&magic, 1, sizeof(magic), fp) != sizeof(magic)) elog(FATAL, "could not write init file"); /* * Write all the appropriate reldescs (in no particular order). */ hash_seq_init(&status, RelationIdCache); while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL) { Relation rel = idhentry->reldesc; Form_pg_class relform = rel->rd_rel; /* ignore if not correct group */ if (relform->relisshared != shared) continue; /* first write the relcache entry proper */ write_item(rel, sizeof(RelationData), fp); /* next write the relation tuple form */ write_item(relform, CLASS_TUPLE_SIZE, fp); /* next, do all the attribute tuple form data entries */ for (i = 0; i < relform->relnatts; i++) { write_item(rel->rd_att->attrs[i], ATTRIBUTE_FIXED_PART_SIZE, fp); } /* next, do the access method specific field */ write_item(rel->rd_options, (rel->rd_options ? VARSIZE(rel->rd_options) : 0), fp); /* If it's an index, there's more to do */ if (rel->rd_rel->relkind == RELKIND_INDEX) { Form_pg_am am = rel->rd_am; /* write the pg_index tuple */ /* we assume this was created by heap_copytuple! */ write_item(rel->rd_indextuple, HEAPTUPLESIZE + rel->rd_indextuple->t_len, fp); /* next, write the access method tuple form */ write_item(am, sizeof(FormData_pg_am), fp); /* next, write the vector of opfamily OIDs */ write_item(rel->rd_opfamily, relform->relnatts * sizeof(Oid), fp); /* next, write the vector of opcintype OIDs */ write_item(rel->rd_opcintype, relform->relnatts * sizeof(Oid), fp); /* next, write the vector of support procedure OIDs */ write_item(rel->rd_support, relform->relnatts * (am->amsupport * sizeof(RegProcedure)), fp); /* next, write the vector of collation OIDs */ write_item(rel->rd_indcollation, relform->relnatts * sizeof(Oid), fp); /* finally, write the vector of indoption values */ write_item(rel->rd_indoption, relform->relnatts * sizeof(int16), fp); } /* also make a list of their OIDs, for RelationIdIsInInitFile */ if (!shared) { oldcxt = MemoryContextSwitchTo(CacheMemoryContext); initFileRelationIds = lcons_oid(RelationGetRelid(rel), initFileRelationIds); MemoryContextSwitchTo(oldcxt); } } if (FreeFile(fp)) elog(FATAL, "could not write init file"); /* * Now we have to check whether the data we've so painstakingly * accumulated is already obsolete due to someone else's just-committed * catalog changes. If so, we just delete the temp file and leave it to * the next backend to try again. (Our own relcache entries will be * updated by SI message processing, but we can't be sure whether what we * wrote out was up-to-date.) * * This mustn't run concurrently with the code that unlinks an init file * and sends SI messages, so grab a serialization lock for the duration. */ LWLockAcquire(RelCacheInitLock, LW_EXCLUSIVE); /* Make sure we have seen all incoming SI messages */ AcceptInvalidationMessages(); /* * If we have received any SI relcache invals since backend start, assume * we may have written out-of-date data. */ if (relcacheInvalsReceived == 0L) { /* * OK, rename the temp file to its final name, deleting any * previously-existing init file. * * Note: a failure here is possible under Cygwin, if some other * backend is holding open an unlinked-but-not-yet-gone init file. So * treat this as a noncritical failure; just remove the useless temp * file on failure. */ if (rename(tempfilename, finalfilename) < 0) unlink(tempfilename); } else { /* Delete the already-obsolete temp file */ unlink(tempfilename); } LWLockRelease(RelCacheInitLock); }
bool criticalRelcachesBuilt = false |
Definition at line 118 of file relcache.c.
Referenced by IndexScanOK(), load_relcache_init_file(), LookupOpclassInfo(), RelationBuildTupleDesc(), RelationCacheInitializePhase3(), RelationReloadIndexInfo(), and ScanPgRelation().
bool criticalSharedRelcachesBuilt = false |
Definition at line 124 of file relcache.c.
Referenced by GetDatabaseTuple(), GetDatabaseTupleByOid(), IndexScanOK(), load_relcache_init_file(), and RelationCacheInitializePhase3().
const FormData_pg_attribute Desc_pg_attribute[Natts_pg_attribute] = {Schema_pg_attribute} [static] |
Definition at line 92 of file relcache.c.
Referenced by RelationCacheInitializePhase3().
const FormData_pg_attribute Desc_pg_auth_members[Natts_pg_auth_members] = {Schema_pg_auth_members} [static] |
Definition at line 97 of file relcache.c.
Referenced by RelationCacheInitializePhase2().
const FormData_pg_attribute Desc_pg_authid[Natts_pg_authid] = {Schema_pg_authid} [static] |
Definition at line 96 of file relcache.c.
Referenced by RelationCacheInitializePhase2().
const FormData_pg_attribute Desc_pg_class[Natts_pg_class] = {Schema_pg_class} [static] |
Definition at line 91 of file relcache.c.
Referenced by GetPgClassDescriptor(), and RelationCacheInitializePhase3().
const FormData_pg_attribute Desc_pg_database[Natts_pg_database] = {Schema_pg_database} [static] |
Definition at line 95 of file relcache.c.
Referenced by RelationCacheInitializePhase2().
const FormData_pg_attribute Desc_pg_index[Natts_pg_index] = {Schema_pg_index} [static] |
Definition at line 98 of file relcache.c.
Referenced by GetPgIndexDescriptor().
const FormData_pg_attribute Desc_pg_proc[Natts_pg_proc] = {Schema_pg_proc} [static] |
Definition at line 93 of file relcache.c.
Referenced by RelationCacheInitializePhase3().
const FormData_pg_attribute Desc_pg_type[Natts_pg_type] = {Schema_pg_type} [static] |
Definition at line 94 of file relcache.c.
Referenced by RelationCacheInitializePhase3().
Oid eoxact_list[MAX_EOXACT_LIST] [static] |
Definition at line 153 of file relcache.c.
Referenced by AtEOSubXact_RelationCache(), and AtEOXact_RelationCache().
int eoxact_list_len = 0 [static] |
Definition at line 154 of file relcache.c.
Referenced by AtEOSubXact_RelationCache(), and AtEOXact_RelationCache().
bool eoxact_list_overflowed = false [static] |
Definition at line 155 of file relcache.c.
Referenced by AtEOSubXact_RelationCache(), and AtEOXact_RelationCache().
List* initFileRelationIds = NIL [static] |
Definition at line 140 of file relcache.c.
HTAB* OpClassCache = NULL [static] |
Definition at line 218 of file relcache.c.
HTAB* RelationIdCache [static] |
Definition at line 112 of file relcache.c.
long relcacheInvalsReceived = 0L [static] |
Definition at line 132 of file relcache.c.
Referenced by RelationCacheInvalidate(), RelationCacheInvalidateEntry(), and write_relcache_init_file().