relcache.c
来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,282 行 · 第 1/5 页
C
2,282 行
static voidRelationBuildTupleDesc(RelationBuildDescInfo buildinfo, Relation relation){ 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; relation->rd_att->tdhasoid = RelationGetForm(relation)->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.) */ ScanKeyEntryInitialize(&skey[0], 0, Anum_pg_attribute_attrelid, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(relation))); ScanKeyEntryInitialize(&skey[1], 0, Anum_pg_attribute_attnum, 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_openr(AttributeRelationName, AccessShareLock); pg_attribute_scan = systable_beginscan(pg_attribute_desc, AttributeRelidNumIndex, 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)); relation->rd_att->attrs[attp->attnum - 1] = (Form_pg_attribute) MemoryContextAlloc(CacheMemoryContext, ATTRIBUTE_TUPLE_SIZE); memcpy((char *) (relation->rd_att->attrs[attp->attnum - 1]), (char *) attp, ATTRIBUTE_TUPLE_SIZE); /* Update constraint/default info */ if (attp->attnotnull) constr->has_not_null = true; if (attp->atthasdef) { if (attrdef == NULL) { attrdef = (AttrDefault *) MemoryContextAlloc(CacheMemoryContext, relation->rd_rel->relnatts * sizeof(AttrDefault)); MemSet(attrdef, 0, 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 *) MemoryContextAlloc(CacheMemoryContext, constr->num_check * sizeof(ConstrCheck)); MemSet(constr->check, 0, constr->num_check * sizeof(ConstrCheck)); CheckConstraintFetch(relation); } else constr->num_check = 0; } else { pfree(constr); relation->rd_att->constr = NULL; }}/* * RelationBuildRuleLock * * Form the relation's rewrite rules from information in * the pg_rewrite system catalog. * * Note: The rule parsetrees are potentially very complex node structures. * To allow these trees to be freed when the relcache entry is flushed, * we make a private memory context to hold the RuleLock information for * each relcache entry that has associated rules. The context is used * just for rule info, not for any other subsidiary data of the relcache * entry, because that keeps the update logic in RelationClearRelation() * manageable. The other subsidiary data structures are simple enough * to be easy to free explicitly, anyway. */static voidRelationBuildRuleLock(Relation relation){ 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 */ ScanKeyEntryInitialize(&key, 0, Anum_pg_rewrite_ev_class, F_OIDEQ, ObjectIdGetDatum(RelationGetRelid(relation))); /* * open pg_rewrite and begin a scan * * Note: since we scan the rules using RewriteRelRulenameIndex, we will * be reading the rules in name order, except possibly during * emergency-recovery operations (ie, IsIgnoringSystemIndexes). This * in turn ensures that rules will be fired in name order. */ rewrite_desc = heap_openr(RewriteRelationName, AccessShareLock); rewrite_tupdesc = RelationGetDescr(rewrite_desc); rewrite_scan = systable_beginscan(rewrite_desc, RewriteRelRulenameIndex, 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 ruleaction; Datum rule_evqual; char *ruleaction_str; char *rule_evqual_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->isInstead = rewrite_form->is_instead; /* Must use heap_getattr to fetch ev_qual and ev_action */ ruleaction = heap_getattr(rewrite_tuple, Anum_pg_rewrite_ev_action, rewrite_tupdesc, &isnull); Assert(!isnull); ruleaction_str = DatumGetCString(DirectFunctionCall1(textout, ruleaction)); oldcxt = MemoryContextSwitchTo(rulescxt); rule->actions = (List *) stringToNode(ruleaction_str); MemoryContextSwitchTo(oldcxt); pfree(ruleaction_str); rule_evqual = heap_getattr(rewrite_tuple, Anum_pg_rewrite_ev_qual, rewrite_tupdesc, &isnull); Assert(!isnull); rule_evqual_str = DatumGetCString(DirectFunctionCall1(textout, rule_evqual)); oldcxt = MemoryContextSwitchTo(rulescxt); rule->qual = (Node *) stringToNode(rule_evqual_str); MemoryContextSwitchTo(oldcxt); pfree(rule_evqual_str); 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); /* * form a RuleLock and insert into relation */ rulelock = (RuleLock *) MemoryContextAlloc(rulescxt, sizeof(RuleLock)); rulelock->numLocks = numlocks; rulelock->rules = rules; relation->rd_rules = rulelock;}/* * equalRuleLocks * * Determine whether two RuleLocks are equivalent * * Probably this should be in the rules code someplace... */static boolequalRuleLocks(RuleLock *rlock1, RuleLock *rlock2){ 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->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;}/* ---------------------------------- * RelationBuildDesc * * Build a relation descriptor --- either a new one, or by * recycling the given old relation object. The latter case * supports rebuilding a relcache entry without invalidating * pointers to it. * -------------------------------- */static RelationRelationBuildDesc(RelationBuildDescInfo buildinfo, Relation oldrelation){ Relation relation; Oid relid; HeapTuple pg_class_tuple; Form_pg_class relp; MemoryContext oldcxt; /* * find the tuple in pg_class corresponding to the given relation id */ pg_class_tuple = ScanPgRelation(buildinfo, 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); /* * allocate storage for the relation descriptor, and copy * pg_class_tuple to relation->rd_rel. */ relation = AllocateRelationDesc(oldrelation, relp); /* * now we can free the memory allocated for pg_class_tuple */ heap_freetuple(pg_class_tuple); /* * initialize the relation's relation id (relation->rd_id) */ RelationGetRelid(relation) = relid; /* * initialize relation->rd_refcnt */ RelationSetReferenceCount(relation, 1); /* * 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_isnailed = 0; relation->rd_isnew = false; relation->rd_istemp = isTempNamespace(relation->rd_rel->relnamespace); /* * initialize the tuple descriptor (relation->rd_att). */ RelationBuildTupleDesc(buildinfo, 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->reltriggers > 0) RelationBuildTriggers(relation); else relation->trigdesc = NULL; /* * if it's an index, initialize index-related information */ if (OidIsValid(relation->rd_rel->relam)) RelationInitIndexAccessInfo(relation); /* * initialize the relation lock manager information */ RelationInitLockInfo(relation); /* see lmgr.c */ if (relation->rd_rel->relisshared) relation->rd_node.tblNode = InvalidOid;
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?