⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 heap.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 4 页
字号:
			ListCell   *cell2;			ccname = cdef->name;			/* Check against pre-existing constraints */			if (ConstraintNameIsUsed(CONSTRAINT_RELATION,									 RelationGetRelid(rel),									 RelationGetNamespace(rel),									 ccname))				ereport(ERROR,						(errcode(ERRCODE_DUPLICATE_OBJECT),				errmsg("constraint \"%s\" for relation \"%s\" already exists",					   ccname, RelationGetRelationName(rel))));			/* Check against other new constraints */			/* Needed because we don't do CommandCounterIncrement in loop */			foreach(cell2, checknames)			{				if (strcmp((char *) lfirst(cell2), ccname) == 0)					ereport(ERROR,							(errcode(ERRCODE_DUPLICATE_OBJECT),							 errmsg("check constraint \"%s\" already exists",									ccname)));			}		}		else		{			/*			 * When generating a name, we want to create "tab_col_check" for a			 * column constraint and "tab_check" for a table constraint.  We			 * no longer have any info about the syntactic positioning of the			 * constraint phrase, so we approximate this by seeing whether the			 * expression references more than one column.	(If the user			 * played by the rules, the result is the same...)			 *			 * Note: pull_var_clause() doesn't descend into sublinks, but we			 * eliminated those above; and anyway this only needs to be an			 * approximate answer.			 */			List	   *vars;			char	   *colname;			vars = pull_var_clause(expr, false);			/* eliminate duplicates */			vars = list_union(NIL, vars);			if (list_length(vars) == 1)				colname = get_attname(RelationGetRelid(rel),									  ((Var *) linitial(vars))->varattno);			else				colname = NULL;			ccname = ChooseConstraintName(RelationGetRelationName(rel),										  colname,										  "check",										  RelationGetNamespace(rel),										  checknames);		}		/* save name for future checks */		checknames = lappend(checknames, ccname);		/*		 * OK, store it.		 */		StoreRelCheck(rel, ccname, nodeToString(expr));		numchecks++;		cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint));		cooked->contype = CONSTR_CHECK;		cooked->name = ccname;		cooked->attnum = 0;		cooked->expr = expr;		cookedConstraints = lappend(cookedConstraints, cooked);	}	/*	 * Update the count of constraints in the relation's pg_class tuple. We do	 * this even if there was no change, in order to ensure that an SI update	 * message is sent out for the pg_class tuple, which will force other	 * backends to rebuild their relcache entries for the rel. (This is	 * critical if we added defaults but not constraints.)	 */	SetRelationNumChecks(rel, numchecks);	return cookedConstraints;}/* * Update the count of constraints in the relation's pg_class tuple. * * Caller had better hold exclusive lock on the relation. * * An important side effect is that a SI update message will be sent out for * the pg_class tuple, which will force other backends to rebuild their * relcache entries for the rel.  Also, this backend will rebuild its * own relcache entry at the next CommandCounterIncrement. */static voidSetRelationNumChecks(Relation rel, int numchecks){	Relation	relrel;	HeapTuple	reltup;	Form_pg_class relStruct;	relrel = heap_open(RelationRelationId, RowExclusiveLock);	reltup = SearchSysCacheCopy(RELOID,								ObjectIdGetDatum(RelationGetRelid(rel)),								0, 0, 0);	if (!HeapTupleIsValid(reltup))		elog(ERROR, "cache lookup failed for relation %u",			 RelationGetRelid(rel));	relStruct = (Form_pg_class) GETSTRUCT(reltup);	if (relStruct->relchecks != numchecks)	{		relStruct->relchecks = numchecks;		simple_heap_update(relrel, &reltup->t_self, reltup);		/* keep catalog indexes current */		CatalogUpdateIndexes(relrel, reltup);	}	else	{		/* Skip the disk update, but force relcache inval anyway */		CacheInvalidateRelcache(rel);	}	heap_freetuple(reltup);	heap_close(relrel, RowExclusiveLock);}/* * Take a raw default and convert it to a cooked format ready for * storage. * * Parse state should be set up to recognize any vars that might appear * in the expression.  (Even though we plan to reject vars, it's more * user-friendly to give the correct error message than "unknown var".) * * If atttypid is not InvalidOid, coerce the expression to the specified * type (and typmod atttypmod).   attname is only needed in this case: * it is used in the error message, if any. */Node *cookDefault(ParseState *pstate,			Node *raw_default,			Oid atttypid,			int32 atttypmod,			char *attname){	Node	   *expr;	Assert(raw_default != NULL);	/*	 * Transform raw parsetree to executable expression.	 */	expr = transformExpr(pstate, raw_default);	/*	 * Make sure default expr does not refer to any vars.	 */	if (contain_var_clause(expr))		ereport(ERROR,				(errcode(ERRCODE_INVALID_COLUMN_REFERENCE),			  errmsg("cannot use column references in default expression")));	/*	 * It can't return a set either.	 */	if (expression_returns_set(expr))		ereport(ERROR,				(errcode(ERRCODE_DATATYPE_MISMATCH),				 errmsg("default expression must not return a set")));	/*	 * No subplans or aggregates, either...	 */	if (pstate->p_hasSubLinks)		ereport(ERROR,				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),				 errmsg("cannot use subquery in default expression")));	if (pstate->p_hasAggs)		ereport(ERROR,				(errcode(ERRCODE_GROUPING_ERROR),			 errmsg("cannot use aggregate function in default expression")));	/*	 * Coerce the expression to the correct type and typmod, if given. This	 * should match the parser's processing of non-defaulted expressions ---	 * see updateTargetListEntry().	 */	if (OidIsValid(atttypid))	{		Oid			type_id = exprType(expr);		expr = coerce_to_target_type(pstate, expr, type_id,									 atttypid, atttypmod,									 COERCION_ASSIGNMENT,									 COERCE_IMPLICIT_CAST);		if (expr == NULL)			ereport(ERROR,					(errcode(ERRCODE_DATATYPE_MISMATCH),					 errmsg("column \"%s\" is of type %s"							" but default expression is of type %s",							attname,							format_type_be(atttypid),							format_type_be(type_id)),			   errhint("You will need to rewrite or cast the expression.")));	}	return expr;}/* * Removes all constraints on a relation that match the given name. * * It is the responsibility of the calling function to acquire a suitable * lock on the relation. * * Returns: The number of constraints removed. */intRemoveRelConstraints(Relation rel, const char *constrName,					 DropBehavior behavior){	int			ndeleted = 0;	Relation	conrel;	SysScanDesc conscan;	ScanKeyData key[1];	HeapTuple	contup;	/* Grab an appropriate lock on the pg_constraint relation */	conrel = heap_open(ConstraintRelationId, RowExclusiveLock);	/* Use the index to scan only constraints of the target relation */	ScanKeyInit(&key[0],				Anum_pg_constraint_conrelid,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(RelationGetRelid(rel)));	conscan = systable_beginscan(conrel, ConstraintRelidIndexId, true,								 SnapshotNow, 1, key);	/*	 * Scan over the result set, removing any matching entries.	 */	while ((contup = systable_getnext(conscan)) != NULL)	{		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(contup);		if (strcmp(NameStr(con->conname), constrName) == 0)		{			ObjectAddress conobj;			conobj.classId = ConstraintRelationId;			conobj.objectId = HeapTupleGetOid(contup);			conobj.objectSubId = 0;			performDeletion(&conobj, behavior);			ndeleted++;		}	}	/* Clean up after the scan */	systable_endscan(conscan);	heap_close(conrel, RowExclusiveLock);	return ndeleted;}/* * RemoveStatistics --- remove entries in pg_statistic for a rel or column * * If attnum is zero, remove all entries for rel; else remove only the one * for that column. */voidRemoveStatistics(Oid relid, AttrNumber attnum){	Relation	pgstatistic;	SysScanDesc scan;	ScanKeyData key[2];	int			nkeys;	HeapTuple	tuple;	pgstatistic = heap_open(StatisticRelationId, RowExclusiveLock);	ScanKeyInit(&key[0],				Anum_pg_statistic_starelid,				BTEqualStrategyNumber, F_OIDEQ,				ObjectIdGetDatum(relid));	if (attnum == 0)		nkeys = 1;	else	{		ScanKeyInit(&key[1],					Anum_pg_statistic_staattnum,					BTEqualStrategyNumber, F_INT2EQ,					Int16GetDatum(attnum));		nkeys = 2;	}	scan = systable_beginscan(pgstatistic, StatisticRelidAttnumIndexId, true,							  SnapshotNow, nkeys, key);	while (HeapTupleIsValid(tuple = systable_getnext(scan)))		simple_heap_delete(pgstatistic, &tuple->t_self);	systable_endscan(scan);	heap_close(pgstatistic, RowExclusiveLock);}/* * RelationTruncateIndexes - truncate all * indexes associated with the heap relation to zero tuples. * * The routine will truncate and then reconstruct the indexes on * the relation specified by the heapId parameter. */static voidRelationTruncateIndexes(Oid heapId){	Relation	heapRelation;	ListCell   *indlist;	/*	 * Open the heap rel.  We need grab no lock because we assume	 * heap_truncate is holding an exclusive lock on the heap rel.	 */	heapRelation = heap_open(heapId, NoLock);	/* Ask the relcache to produce a list of the indexes of the rel */	foreach(indlist, RelationGetIndexList(heapRelation))	{		Oid			indexId = lfirst_oid(indlist);		Relation	currentIndex;		IndexInfo  *indexInfo;		/* Open the index relation */		currentIndex = index_open(indexId);		/* Obtain exclusive lock on it, just to be sure */		LockRelation(currentIndex, AccessExclusiveLock);		/* Fetch info needed for index_build */		indexInfo = BuildIndexInfo(currentIndex);		/* Now truncate the actual file (and discard buffers) */		RelationTruncate(currentIndex, 0);		/* Initialize the index and rebuild */		index_build(heapRelation, currentIndex, indexInfo);		/*		 * index_build will close both the heap and index relations (but not		 * give up the locks we hold on them).	We're done with this index,		 * but we must re-open the heap rel.		 */		heapRelation = heap_open(heapId, NoLock);	}	/* Finish by closing the heap rel again */	heap_close(heapRelation, NoLock);}/* *	 heap_truncate * *	 This routine deletes all data within all the specified relations. * * This is not transaction-safe!  There is another, transaction-safe * implementation in commands/tablecmds.c.	We now use this only for * ON COMMIT truncation of temporary tables, where it doesn't matter. */voidheap_truncate(List *relids){	List	   *relations = NIL;	ListCell   *cell;	/* Open relations for processing, and grab exclusive access on each */	foreach(cell, relids)	{		Oid			rid = lfirst_oid(cell);		Relation	rel;		Oid			toastrelid;		rel = heap_open(rid, AccessExclusiveLock);		relations = lappend(relations, rel);		/* If there is a toast table, add it to the list too */		toastrelid = rel->rd_rel->reltoastrelid;		if (OidIsValid(toastrelid))		{			rel = heap_open(toastrelid, AccessExclusiveLock);			relations = lappend(relations, rel);		}	}	/* Don't allow truncate on tables that are referenced by foreign keys */	heap_truncate_check_FKs(relations, true);	/* OK to do it */	foreach(cell, relations)	{		Relation	rel = lfirst(cell);		/* Truncate the actual file (and discard buffers) */		RelationTruncate(rel, 0);		/* If this relation has indexes, truncate the indexes too */		RelationTruncateIndexes(RelationGetRelid(rel));		/*		 * Close the relation, but keep exclusive lock on it until commit.		 */		heap_close(rel, NoLock);	}}/* * heap_truncate_check_FKs *		Check for foreign keys referencing a list of relations that *		are to be truncated * * We disallow such FKs (except self-referential ones) since the whole point * of TRUNCATE is to not scan the individual rows to be thrown away. * * This is split out so it can be shared by both implementations of truncate. * Caller should already hold a suitable lock on the relations. * * tempTables is only used to select an appropriate error message. */voidheap_truncate_check_FKs(List *relations, bool tempTables){	List	   *oids = NIL;	ListCell   *cell;	Relation	fkeyRel;	SysScanDesc fkeyScan;	HeapTuple	tuple;	/*	 * Build a list of OIDs of the interesting relations.	 *	 * If a relation has no triggers, then it can neither have FKs nor be	 * referenced by a FK from another table, so we can ignore it.	 */	foreach(cell, relations)	{		Relation	rel = lfirst(cell);		if (rel->rd_rel->reltriggers != 0)			oids = lappend_oid(oids, RelationGetRelid(rel));	}	/*	 * Fast path: if no relation has triggers, none has FKs either.	 */	if (oids == NIL)		return;	/*	 * Otherwise, must scan pg_constraint.	Right now, it is a seqscan because	 * there is no available index on confrelid.	 */	fkeyRel = heap_open(ConstraintRelationId, AccessShareLock);	fkeyScan = systable_beginscan(fkeyRel, InvalidOid, false,								  SnapshotNow, 0, NULL);	while (HeapTupleIsValid(tuple = systable_getnext(fkeyScan)))	{		Form_pg_constraint con = (Form_pg_constraint) GETSTRUCT(tuple);		/* Not a foreign key */		if (con->contype != CONSTRAINT_FOREIGN)			continue;		/* Not for one of our list of tables */		if (!list_member_oid(oids, con->confrelid))			continue;		/* The referencer should be in our list too */		if (!list_member_oid(oids, con->conrelid))		{			if (tempTables)				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),				 errmsg("unsupported ON COMMIT and foreign key combination"),						 errdetail("Table \"%s\" references \"%s\" via foreign key constraint \"%s\", but they do not have the same ON COMMIT setting.",								   get_rel_name(con->conrelid),								   get_rel_name(con->confrelid),								   NameStr(con->conname))));			else				ereport(ERROR,						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),						 errmsg("cannot truncate a table referenced in a foreign key constraint"),						 errdetail("Table \"%s\" references \"%s\" via foreign key constraint \"%s\".",								   get_rel_name(con->conrelid),								   get_rel_name(con->confrelid),								   NameStr(con->conname)),						 errhint("Truncate table \"%s\" at the same time.",								 get_rel_name(con->conrelid))));		}	}	systable_endscan(fkeyScan);	heap_close(fkeyRel, AccessShareLock);}

⌨️ 快捷键说明

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