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 + -
显示快捷键?