#include "access/tupdesc.h"
#include "nodes/bitmapset.h"
Go to the source code of this file.
typedef struct RelationData* Relation |
Definition at line 21 of file relcache.h.
typedef Relation* RelationPtr |
Definition at line 29 of file relcache.h.
void AtEOSubXact_RelationCache | ( | bool | isCommit, | |
SubTransactionId | mySubid, | |||
SubTransactionId | parentSubid | |||
) |
Definition at line 2438 of file relcache.c.
References AtEOSubXact_cleanup(), eoxact_list, eoxact_list_len, eoxact_list_overflowed, hash_search(), hash_seq_init(), hash_seq_search(), i, NULL, and relidcacheent::reldesc.
Referenced by AbortSubTransaction(), and CommitSubTransaction().
{ HASH_SEQ_STATUS status; RelIdCacheEnt *idhentry; int i; /* * Unless the eoxact_list[] overflowed, we only need to examine the rels * listed in it. Otherwise fall back on a hash_seq_search scan. Same * logic as in AtEOXact_RelationCache. */ if (eoxact_list_overflowed) { hash_seq_init(&status, RelationIdCache); while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL) { AtEOSubXact_cleanup(idhentry->reldesc, isCommit, mySubid, parentSubid); } } else { for (i = 0; i < eoxact_list_len; i++) { idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache, (void *) &eoxact_list[i], HASH_FIND, NULL); if (idhentry != NULL) AtEOSubXact_cleanup(idhentry->reldesc, isCommit, mySubid, parentSubid); } } /* Don't reset the list; we still need more cleanup later */ }
void AtEOXact_RelationCache | ( | bool | isCommit | ) |
Definition at line 2314 of file relcache.c.
References AtEOXact_cleanup(), eoxact_list, eoxact_list_len, eoxact_list_overflowed, hash_search(), hash_seq_init(), hash_seq_search(), i, NULL, and relidcacheent::reldesc.
Referenced by AbortTransaction(), CommitTransaction(), and PrepareTransaction().
{ HASH_SEQ_STATUS status; RelIdCacheEnt *idhentry; int i; /* * Unless the eoxact_list[] overflowed, we only need to examine the rels * listed in it. Otherwise fall back on a hash_seq_search scan. * * For simplicity, eoxact_list[] entries are not deleted till end of * top-level transaction, even though we could remove them at * subtransaction end in some cases, or remove relations from the list if * they are cleared for other reasons. Therefore we should expect the * case that list entries are not found in the hashtable; if not, there's * nothing to do for them. */ if (eoxact_list_overflowed) { hash_seq_init(&status, RelationIdCache); while ((idhentry = (RelIdCacheEnt *) hash_seq_search(&status)) != NULL) { AtEOXact_cleanup(idhentry->reldesc, isCommit); } } else { for (i = 0; i < eoxact_list_len; i++) { idhentry = (RelIdCacheEnt *) hash_search(RelationIdCache, (void *) &eoxact_list[i], HASH_FIND, NULL); if (idhentry != NULL) AtEOXact_cleanup(idhentry->reldesc, isCommit); } } /* Now we're out of the transaction and can clear the list */ eoxact_list_len = 0; eoxact_list_overflowed = false; }
int errtable | ( | Relation | rel | ) |
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 */ }
Relation RelationBuildLocalRelation | ( | const char * | relname, | |
Oid | relnamespace, | |||
TupleDesc | tupDesc, | |||
Oid | relid, | |||
Oid | relfilenode, | |||
Oid | reltablespace, | |||
bool | shared_relation, | |||
bool | mapped_relation, | |||
char | relpersistence, | |||
char | relkind | |||
) |
Definition at line 2536 of file relcache.c.
References Assert, AssertArg, AttributeRelationId, tupleDesc::attrs, AuthIdRelationId, AuthMemRelationId, CacheMemoryContext, CLASS_TUPLE_SIZE, tupleDesc::constr, CreateCacheMemoryContext(), CreateTupleDescCopy(), DatabaseRelationId, elog, EOXactListAdd, ERROR, GetCurrentSubTransactionId(), tupleConstr::has_not_null, i, IsSharedRelation(), isTempOrToastNamespace(), MemoryContextSwitchTo(), MyBackendId, namestrcpy(), tupleDesc::natts, palloc0(), ProcedureRelationId, RelationData::rd_att, RelationData::rd_backend, RelationData::rd_createSubid, RelationData::rd_islocaltemp, RelationData::rd_isnailed, RelationData::rd_ispopulated, RelationData::rd_isvalid, RelationData::rd_newRelfilenodeSubid, RelationData::rd_refcnt, RelationData::rd_rel, RelationData::rd_smgr, RelationCacheInsert, RelationGetRelid, RelationIncrementReferenceCount(), RelationInitLockInfo(), RelationInitPhysicalAddr(), RelationMapUpdateMap(), RelationRelationId, RELKIND_MATVIEW, RELPERSISTENCE_PERMANENT, RELPERSISTENCE_TEMP, RELPERSISTENCE_UNLOGGED, tupleDesc::tdhasoid, tupleDesc::tdrefcount, and TypeRelationId.
Referenced by heap_create().
{ Relation rel; MemoryContext oldcxt; int natts = tupDesc->natts; int i; bool has_not_null; bool nailit; AssertArg(natts >= 0); /* * check for creation of a rel that must be nailed in cache. * * XXX this list had better match the relations specially handled in * RelationCacheInitializePhase2/3. */ switch (relid) { case DatabaseRelationId: case AuthIdRelationId: case AuthMemRelationId: case RelationRelationId: case AttributeRelationId: case ProcedureRelationId: case TypeRelationId: nailit = true; break; default: nailit = false; break; } /* * check that hardwired list of shared rels matches what's in the * bootstrap .bki file. If you get a failure here during initdb, you * probably need to fix IsSharedRelation() to match whatever you've done * to the set of shared relations. */ if (shared_relation != IsSharedRelation(relid)) elog(ERROR, "shared_relation flag for \"%s\" does not match IsSharedRelation(%u)", relname, relid); /* Shared relations had better be mapped, too */ Assert(mapped_relation || !shared_relation); /* * switch to the cache context to create the relcache entry. */ if (!CacheMemoryContext) CreateCacheMemoryContext(); oldcxt = MemoryContextSwitchTo(CacheMemoryContext); /* * allocate a new relation descriptor and fill in basic state fields. */ rel = (Relation) palloc0(sizeof(RelationData)); /* make sure relation is marked as having no open file yet */ rel->rd_smgr = NULL; /* mark it nailed if appropriate */ rel->rd_isnailed = nailit; rel->rd_refcnt = nailit ? 1 : 0; /* it's being created in this transaction */ rel->rd_createSubid = GetCurrentSubTransactionId(); rel->rd_newRelfilenodeSubid = InvalidSubTransactionId; /* * create a new tuple descriptor from the one passed in. We do this * partly to copy it into the cache context, and partly because the new * relation can't have any defaults or constraints yet; they have to be * added in later steps, because they require additions to multiple system * catalogs. We can copy attnotnull constraints here, however. */ rel->rd_att = CreateTupleDescCopy(tupDesc); rel->rd_att->tdrefcount = 1; /* mark as refcounted */ has_not_null = false; for (i = 0; i < natts; i++) { rel->rd_att->attrs[i]->attnotnull = tupDesc->attrs[i]->attnotnull; has_not_null |= tupDesc->attrs[i]->attnotnull; } if (has_not_null) { TupleConstr *constr = (TupleConstr *) palloc0(sizeof(TupleConstr)); constr->has_not_null = true; rel->rd_att->constr = constr; } /* * initialize relation tuple form (caller may add/override data later) */ rel->rd_rel = (Form_pg_class) palloc0(CLASS_TUPLE_SIZE); namestrcpy(&rel->rd_rel->relname, relname); rel->rd_rel->relnamespace = relnamespace; rel->rd_rel->relkind = relkind; rel->rd_rel->relhasoids = rel->rd_att->tdhasoid; rel->rd_rel->relnatts = natts; rel->rd_rel->reltype = InvalidOid; /* needed when bootstrapping: */ rel->rd_rel->relowner = BOOTSTRAP_SUPERUSERID; /* set up persistence and relcache fields dependent on it */ rel->rd_rel->relpersistence = relpersistence; switch (relpersistence) { case RELPERSISTENCE_UNLOGGED: case RELPERSISTENCE_PERMANENT: rel->rd_backend = InvalidBackendId; rel->rd_islocaltemp = false; break; case RELPERSISTENCE_TEMP: Assert(isTempOrToastNamespace(relnamespace)); rel->rd_backend = MyBackendId; rel->rd_islocaltemp = true; break; default: elog(ERROR, "invalid relpersistence: %c", relpersistence); break; } /* * Insert relation physical and logical identifiers (OIDs) into the right * places. For a mapped relation, we set relfilenode to zero and rely on * RelationInitPhysicalAddr to consult the map. */ rel->rd_rel->relisshared = shared_relation; RelationGetRelid(rel) = relid; for (i = 0; i < natts; i++) rel->rd_att->attrs[i]->attrelid = relid; rel->rd_rel->reltablespace = reltablespace; if (mapped_relation) { rel->rd_rel->relfilenode = InvalidOid; /* Add it to the active mapping information */ RelationMapUpdateMap(relid, relfilenode, shared_relation, true); } else rel->rd_rel->relfilenode = relfilenode; RelationInitLockInfo(rel); /* see lmgr.c */ RelationInitPhysicalAddr(rel); /* materialized view not initially scannable */ if (relkind == RELKIND_MATVIEW) rel->rd_ispopulated = false; else rel->rd_ispopulated = true; /* * Okay to insert into the relcache hash tables. */ RelationCacheInsert(rel); /* * Flag relation as needing eoxact cleanup (to clear rd_createSubid). * We can't do this before storing relid in it. */ EOXactListAdd(rel); /* * done building relcache entry. */ MemoryContextSwitchTo(oldcxt); /* It's fully valid */ rel->rd_isvalid = true; /* * Caller expects us to pin the returned entry. */ RelationIncrementReferenceCount(rel); return rel; }
void RelationCacheInitFilePostInvalidate | ( | void | ) |
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); }
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); } }
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 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 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; }
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 118 of file relcache.c.
Referenced by IndexScanOK(), load_relcache_init_file(), LookupOpclassInfo(), RelationBuildTupleDesc(), RelationCacheInitializePhase3(), RelationReloadIndexInfo(), and ScanPgRelation().
Definition at line 124 of file relcache.c.
Referenced by GetDatabaseTuple(), GetDatabaseTupleByOid(), IndexScanOK(), load_relcache_init_file(), and RelationCacheInitializePhase3().