heap.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 2,069 行 · 第 1/4 页

C
2,069
字号
						   ObjectIdGetDatum(relid));	ScanKeyEntryInitialize(&scankeys[1], 0x0,						   Anum_pg_attrdef_adnum, F_INT2EQ,						   Int16GetDatum(attnum));	scan = systable_beginscan(attrdef_rel, AttrDefaultIndex, true,							  SnapshotNow, 2, scankeys);	/* There should be at most one matching tuple, but we loop anyway */	while (HeapTupleIsValid(tuple = systable_getnext(scan)))	{		ObjectAddress object;		object.classId = RelationGetRelid(attrdef_rel);		object.objectId = HeapTupleGetOid(tuple);		object.objectSubId = 0;		performDeletion(&object, behavior);		found = true;	}	systable_endscan(scan);	heap_close(attrdef_rel, RowExclusiveLock);	if (complain && !found)		elog(ERROR, "could not find attrdef tuple for relation %u attnum %d",			 relid, attnum);}/* *		RemoveAttrDefaultById * * Remove a pg_attrdef entry specified by OID.	This is the guts of * attribute-default removal.  Note it should be called via performDeletion, * not directly. */voidRemoveAttrDefaultById(Oid attrdefId){	Relation	attrdef_rel;	Relation	attr_rel;	Relation	myrel;	ScanKeyData scankeys[1];	SysScanDesc scan;	HeapTuple	tuple;	Oid			myrelid;	AttrNumber	myattnum;	/* Grab an appropriate lock on the pg_attrdef relation */	attrdef_rel = heap_openr(AttrDefaultRelationName, RowExclusiveLock);	/* Find the pg_attrdef tuple */	ScanKeyEntryInitialize(&scankeys[0], 0x0,						   ObjectIdAttributeNumber, F_OIDEQ,						   ObjectIdGetDatum(attrdefId));	scan = systable_beginscan(attrdef_rel, AttrDefaultOidIndex, true,							  SnapshotNow, 1, scankeys);	tuple = systable_getnext(scan);	if (!HeapTupleIsValid(tuple))		elog(ERROR, "could not find tuple for attrdef %u", attrdefId);	myrelid = ((Form_pg_attrdef) GETSTRUCT(tuple))->adrelid;	myattnum = ((Form_pg_attrdef) GETSTRUCT(tuple))->adnum;	/* Get an exclusive lock on the relation owning the attribute */	myrel = relation_open(myrelid, AccessExclusiveLock);	/* Now we can delete the pg_attrdef row */	simple_heap_delete(attrdef_rel, &tuple->t_self);	systable_endscan(scan);	heap_close(attrdef_rel, RowExclusiveLock);	/* Fix the pg_attribute row */	attr_rel = heap_openr(AttributeRelationName, RowExclusiveLock);	tuple = SearchSysCacheCopy(ATTNUM,							   ObjectIdGetDatum(myrelid),							   Int16GetDatum(myattnum),							   0, 0);	if (!HeapTupleIsValid(tuple))		/* shouldn't happen */		elog(ERROR, "cache lookup failed for attribute %d of relation %u",			 myattnum, myrelid);	((Form_pg_attribute) GETSTRUCT(tuple))->atthasdef = false;	simple_heap_update(attr_rel, &tuple->t_self, tuple);	/* keep the system catalog indexes current */	CatalogUpdateIndexes(attr_rel, tuple);	/*	 * Our update of the pg_attribute row will force a relcache rebuild,	 * so there's nothing else to do here.	 */	heap_close(attr_rel, RowExclusiveLock);	/* Keep lock on attribute's rel until end of xact */	relation_close(myrel, NoLock);}/* ---------------------------------------------------------------- *		heap_drop_with_catalog	- removes specified relation from catalogs * *		1)	open relation, acquire exclusive lock. *		2)	flush relation buffers from bufmgr *		3)	remove inheritance information *		4)	remove pg_statistic tuples *		5)	remove pg_attribute tuples *		6)	remove pg_class tuple *		7)	unlink relation file * * Note that this routine is not responsible for dropping objects that are * linked to the pg_class entry via dependencies (for example, indexes and * constraints).  Those are deleted by the dependency-tracing logic in * dependency.c before control gets here.  In general, therefore, this routine * should never be called directly; go through performDeletion() instead. * ---------------------------------------------------------------- */voidheap_drop_with_catalog(Oid rid){	Relation	rel;	int			i;	/*	 * Open and lock the relation.	 */	rel = relation_open(rid, AccessExclusiveLock);	/*	 * Release all buffers that belong to this relation, after writing any	 * that are dirty	 */	i = FlushRelationBuffers(rel, (BlockNumber) 0);	if (i < 0)		elog(ERROR, "FlushRelationBuffers returned %d", i);	/*	 * remove inheritance information	 */	RelationRemoveInheritance(rel);	/*	 * delete statistics	 */	RemoveStatistics(rel, 0);	/*	 * delete attribute tuples	 */	DeleteAttributeTuples(RelationGetRelid(rel));	/*	 * delete relation tuple	 */	DeleteRelationTuple(RelationGetRelid(rel));	/*	 * forget any ON COMMIT action for the rel	 */	remove_on_commit_action(rid);	/*	 * unlink the relation's physical file and finish up.	 */	if (rel->rd_rel->relkind != RELKIND_VIEW &&		rel->rd_rel->relkind != RELKIND_COMPOSITE_TYPE)		smgrunlink(DEFAULT_SMGR, rel);	/*	 * Close relcache entry, but *keep* AccessExclusiveLock on the	 * relation until transaction commit.  This ensures no one else will	 * try to do something with the doomed relation.	 */	relation_close(rel, NoLock);	/*	 * flush the relation from the relcache	 */	RelationForgetRelation(rid);}/* * Store a default expression for column attnum of relation rel. * The expression must be presented as a nodeToString() string. */static voidStoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin){	Node	   *expr;	char	   *adsrc;	Relation	adrel;	HeapTuple	tuple;	Datum		values[4];	static char nulls[4] = {' ', ' ', ' ', ' '};	Relation	attrrel;	HeapTuple	atttup;	Form_pg_attribute attStruct;	Oid			attrdefOid;	ObjectAddress colobject,				defobject;	/*	 * Need to construct source equivalent of given node-string.	 */	expr = stringToNode(adbin);	/*	 * deparse it	 */	adsrc = deparse_expression(expr,						deparse_context_for(RelationGetRelationName(rel),											RelationGetRelid(rel)),							   false, false);	/*	 * Make the pg_attrdef entry.	 */	values[Anum_pg_attrdef_adrelid - 1] = RelationGetRelid(rel);	values[Anum_pg_attrdef_adnum - 1] = attnum;	values[Anum_pg_attrdef_adbin - 1] = DirectFunctionCall1(textin,												 CStringGetDatum(adbin));	values[Anum_pg_attrdef_adsrc - 1] = DirectFunctionCall1(textin,												 CStringGetDatum(adsrc));	adrel = heap_openr(AttrDefaultRelationName, RowExclusiveLock);	tuple = heap_formtuple(adrel->rd_att, values, nulls);	attrdefOid = simple_heap_insert(adrel, tuple);	CatalogUpdateIndexes(adrel, tuple);	defobject.classId = RelationGetRelid(adrel);	defobject.objectId = attrdefOid;	defobject.objectSubId = 0;	heap_close(adrel, RowExclusiveLock);	/* now can free some of the stuff allocated above */	pfree(DatumGetPointer(values[Anum_pg_attrdef_adbin - 1]));	pfree(DatumGetPointer(values[Anum_pg_attrdef_adsrc - 1]));	heap_freetuple(tuple);	pfree(adsrc);	/*	 * Update the pg_attribute entry for the column to show that a default	 * exists.	 */	attrrel = heap_openr(AttributeRelationName, RowExclusiveLock);	atttup = SearchSysCacheCopy(ATTNUM,								ObjectIdGetDatum(RelationGetRelid(rel)),								Int16GetDatum(attnum),								0, 0);	if (!HeapTupleIsValid(atttup))		elog(ERROR, "cache lookup failed for attribute %d of relation %u",			 attnum, RelationGetRelid(rel));	attStruct = (Form_pg_attribute) GETSTRUCT(atttup);	if (!attStruct->atthasdef)	{		attStruct->atthasdef = true;		simple_heap_update(attrrel, &atttup->t_self, atttup);		/* keep catalog indexes current */		CatalogUpdateIndexes(attrrel, atttup);	}	heap_close(attrrel, RowExclusiveLock);	heap_freetuple(atttup);	/*	 * Make a dependency so that the pg_attrdef entry goes away if the	 * column (or whole table) is deleted.	 */	colobject.classId = RelOid_pg_class;	colobject.objectId = RelationGetRelid(rel);	colobject.objectSubId = attnum;	recordDependencyOn(&defobject, &colobject, DEPENDENCY_AUTO);	/*	 * Record dependencies on objects used in the expression, too.	 */	recordDependencyOnExpr(&defobject, expr, NIL, DEPENDENCY_NORMAL);}/* * Store a check-constraint expression for the given relation. * The expression must be presented as a nodeToString() string. * * Caller is responsible for updating the count of constraints * in the pg_class entry for the relation. */static voidStoreRelCheck(Relation rel, char *ccname, char *ccbin){	Node	   *expr;	char	   *ccsrc;	List	   *varList;	int			keycount;	int16	   *attNos;	/*	 * Convert condition to a normal boolean expression tree.	 */	expr = stringToNode(ccbin);	expr = (Node *) make_ands_explicit((List *) expr);	/*	 * deparse it	 */	ccsrc = deparse_expression(expr,						deparse_context_for(RelationGetRelationName(rel),											RelationGetRelid(rel)),							   false, false);	/*	 * Find columns of rel that are used in ccbin	 *	 * NB: pull_var_clause is okay here only because we don't allow	 * subselects in check constraints; it would fail to examine the	 * contents of subselects.	 */	varList = pull_var_clause(expr, false);	keycount = length(varList);	if (keycount > 0)	{		List	   *vl;		int			i = 0;		attNos = (int16 *) palloc(keycount * sizeof(int16));		foreach(vl, varList)		{			Var		   *var = (Var *) lfirst(vl);			int			j;			for (j = 0; j < i; j++)				if (attNos[j] == var->varattno)					break;			if (j == i)				attNos[i++] = var->varattno;		}		keycount = i;	}	else		attNos = NULL;	/*	 * Create the Check Constraint	 */	CreateConstraintEntry(ccname,		/* Constraint Name */						  RelationGetNamespace(rel),	/* namespace */						  CONSTRAINT_CHECK,		/* Constraint Type */						  false,	/* Is Deferrable */						  false,	/* Is Deferred */						  RelationGetRelid(rel),		/* relation */						  attNos,		/* attrs in the constraint */						  keycount,		/* # attrs in the constraint */						  InvalidOid,	/* not a domain constraint */						  InvalidOid,	/* Foreign key fields */						  NULL,						  0,						  ' ',						  ' ',						  ' ',						  InvalidOid,	/* no associated index */						  expr, /* Tree form check constraint */						  ccbin,	/* Binary form check constraint */						  ccsrc);		/* Source form check constraint */	pfree(ccsrc);}/* * Store defaults and constraints passed in via the tuple constraint struct. * * NOTE: only pre-cooked expressions will be passed this way, which is to * say expressions inherited from an existing relation.  Newly parsed * expressions can be added later, by direct calls to StoreAttrDefault * and StoreRelCheck (see AddRelationRawConstraints()). */static voidStoreConstraints(Relation rel, TupleDesc tupdesc){	TupleConstr *constr = tupdesc->constr;	int			i;	if (!constr)		return;					/* nothing to do */	/*	 * Deparsing of constraint expressions will fail unless the	 * just-created pg_attribute tuples for this relation are made	 * visible.  So, bump the command counter.	CAUTION: this will cause a	 * relcache entry rebuild.	 */	CommandCounterIncrement();	for (i = 0; i < constr->num_defval; i++)		StoreAttrDefault(rel, constr->defval[i].adnum,						 constr->defval[i].adbin);	for (i = 0; i < constr->num_check; i++)		StoreRelCheck(rel, constr->check[i].ccname,					  constr->check[i].ccbin);	if (constr->num_check > 0)		SetRelationNumChecks(rel, constr->num_check);}/* * AddRelationRawConstraints * * Add raw (not-yet-transformed) column default expressions and/or constraint * check expressions to an existing relation.  This is defined to do both * for efficiency in DefineRelation, but of course you can do just one or * the other by passing empty lists. * * rel: relation to be modified * rawColDefaults: list of RawColumnDefault structures * rawConstraints: list of Constraint nodes * * All entries in rawColDefaults will be processed.  Entries in rawConstraints * will be processed only if they are CONSTR_CHECK type and contain a "raw" * expression. * * NB: caller should have opened rel with AccessExclusiveLock, and should * hold that lock till end of transaction.	Also, we assume the caller has * done a CommandCounterIncrement if necessary to make the relation's catalog * tuples visible. */voidAddRelationRawConstraints(Relation rel,						  List *rawColDefaults,						  List *rawConstraints){	char	   *relname = RelationGetRelationName(rel);	TupleDesc	tupleDesc;	TupleConstr *oldconstr;	int			numoldchecks;	ConstrCheck *oldchecks;	ParseState *pstate;	RangeTblEntry *rte;	int			numchecks;	int			constr_name_ctr = 0;	List	   *listptr;	Node	   *expr;	/*	 * Get info about existing constraints.	 */	tupleDesc = RelationGetDescr(rel);	oldconstr = tupleDesc->constr;	if (oldconstr)	{		numoldchecks = oldconstr->num_check;		oldchecks = oldconstr->check;	}	else	{		numoldchecks = 0;		oldchecks = NULL;	}	/*	 * Create a dummy ParseState and insert the target relation as its	 * sole rangetable entry.  We need a ParseState for transformExpr.	 */	pstate = make_parsestate(NULL);	rte = addRangeTableEntryForRelation(pstate,										RelationGetRelid(rel),										makeAlias(relname, NIL),										false,										true);	addRTEtoQuery(pstate, rte, true, true);	/*	 * Process column default expressions.	 */	foreach(listptr, rawColDefaults)	{		RawColumnDefault *colDef = (RawColumnDefault *) lfirst(listptr);		Form_pg_attribute atp = rel->rd_att->attrs[colDef->attnum - 1];		expr = cookDefault(pstate, colDef->raw_default,						   atp->atttypid, atp->atttypmod,						   NameStr(atp->attname));		StoreAttrDefault(rel, colDef->attnum, nodeToString(expr));	}	/*	 * Process constraint expressions.	 */	numchecks = numoldchecks;	foreach(listptr, rawConstraints)	{		Constraint *cdef = (Constraint *) lfirst(listptr);		char	   *ccname;		if (cdef->contype != CONSTR_CHECK || cdef->raw_expr == NULL)			continue;		Assert(cdef->cooked_expr == NULL);		/* Check name uniqueness, or generate a new name */		if (cdef->name != NULL)		{			List	   *listptr2;			ccname = cdef->name;			/* Check against pre-existing constraints */			if (ConstraintNameIsUsed(CONSTRAINT_RELATION,									 RelationGetRelid(rel),									 RelationGetNamespace(rel),									 ccname))				ereport(ERROR,

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?