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

📄 execmain.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
 *		index relations. * ---------------------------------------------------------------- */static voidExecInsert(TupleTableSlot *slot,		   ItemPointer tupleid,		   EState *estate){	HeapTuple	tuple;	ResultRelInfo *resultRelInfo;	Relation	resultRelationDesc;	Oid			newId;	/*	 * get the heap tuple out of the tuple table slot, making sure we have a	 * writable copy	 */	tuple = ExecMaterializeSlot(slot);	/*	 * get information on the (current) result relation	 */	resultRelInfo = estate->es_result_relation_info;	resultRelationDesc = resultRelInfo->ri_RelationDesc;	/* BEFORE ROW INSERT Triggers */	if (resultRelInfo->ri_TrigDesc &&		resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_INSERT] > 0)	{		HeapTuple	newtuple;		newtuple = ExecBRInsertTriggers(estate, resultRelInfo, tuple);		if (newtuple == NULL)	/* "do nothing" */			return;		if (newtuple != tuple)	/* modified by Trigger(s) */		{			/*			 * Put the modified tuple into a slot for convenience of routines			 * below.  We assume the tuple was allocated in per-tuple memory			 * context, and therefore will go away by itself. The tuple table			 * slot should not try to clear it.			 */			TupleTableSlot *newslot = estate->es_trig_tuple_slot;			if (newslot->tts_tupleDescriptor != slot->tts_tupleDescriptor)				ExecSetSlotDescriptor(newslot,									  slot->tts_tupleDescriptor,									  false);			ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);			slot = newslot;			tuple = newtuple;		}	}	/*	 * Check the constraints of the tuple	 */	if (resultRelationDesc->rd_att->constr)		ExecConstraints(resultRelInfo, slot, estate);	/*	 * insert the tuple	 *	 * Note: heap_insert returns the tid (location) of the new tuple in the	 * t_self field.	 */	newId = heap_insert(resultRelationDesc, tuple,						estate->es_snapshot->curcid,						true, true);	IncrAppended();	(estate->es_processed)++;	estate->es_lastoid = newId;	setLastTid(&(tuple->t_self));	/*	 * insert index entries for tuple	 */	if (resultRelInfo->ri_NumIndices > 0)		ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);	/* AFTER ROW INSERT Triggers */	ExecARInsertTriggers(estate, resultRelInfo, tuple);}/* ---------------------------------------------------------------- *		ExecDelete * *		DELETE is like UPDATE, we delete the tuple and its *		index tuples. * ---------------------------------------------------------------- */static voidExecDelete(TupleTableSlot *slot,		   ItemPointer tupleid,		   EState *estate){	ResultRelInfo *resultRelInfo;	Relation	resultRelationDesc;	HTSU_Result result;	ItemPointerData update_ctid;	TransactionId update_xmax;	/*	 * get information on the (current) result relation	 */	resultRelInfo = estate->es_result_relation_info;	resultRelationDesc = resultRelInfo->ri_RelationDesc;	/* BEFORE ROW DELETE Triggers */	if (resultRelInfo->ri_TrigDesc &&		resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_DELETE] > 0)	{		bool		dodelete;		dodelete = ExecBRDeleteTriggers(estate, resultRelInfo, tupleid,										estate->es_snapshot->curcid);		if (!dodelete)			/* "do nothing" */			return;	}	/*	 * delete the tuple	 *	 * Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check that	 * the row to be deleted is visible to that snapshot, and throw a can't-	 * serialize error if not.	This is a special-case behavior needed for	 * referential integrity updates in serializable transactions.	 */ldelete:;	result = heap_delete(resultRelationDesc, tupleid,						 &update_ctid, &update_xmax,						 estate->es_snapshot->curcid,						 estate->es_crosscheck_snapshot,						 true /* wait for commit */ );	switch (result)	{		case HeapTupleSelfUpdated:			/* already deleted by self; nothing to do */			return;		case HeapTupleMayBeUpdated:			break;		case HeapTupleUpdated:			if (IsXactIsoLevelSerializable)				ereport(ERROR,						(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),						 errmsg("could not serialize access due to concurrent update")));			else if (!ItemPointerEquals(tupleid, &update_ctid))			{				TupleTableSlot *epqslot;				epqslot = EvalPlanQual(estate,									   resultRelInfo->ri_RangeTableIndex,									   &update_ctid,									   update_xmax,									   estate->es_snapshot->curcid);				if (!TupIsNull(epqslot))				{					*tupleid = update_ctid;					goto ldelete;				}			}			/* tuple already deleted; nothing to do */			return;		default:			elog(ERROR, "unrecognized heap_delete status: %u", result);			return;	}	IncrDeleted();	(estate->es_processed)++;	/*	 * Note: Normally one would think that we have to delete index tuples	 * associated with the heap tuple now..	 *	 * ... but in POSTGRES, we have no need to do this because the vacuum	 * daemon automatically opens an index scan and deletes index tuples when	 * it finds deleted heap tuples. -cim 9/27/89	 */	/* AFTER ROW DELETE Triggers */	ExecARDeleteTriggers(estate, resultRelInfo, tupleid);}/* ---------------------------------------------------------------- *		ExecUpdate * *		note: we can't run UPDATE queries with transactions *		off because UPDATEs are actually INSERTs and our *		scan will mistakenly loop forever, updating the tuple *		it just inserted..	This should be fixed but until it *		is, we don't want to get stuck in an infinite loop *		which corrupts your database.. * ---------------------------------------------------------------- */static voidExecUpdate(TupleTableSlot *slot,		   ItemPointer tupleid,		   EState *estate){	HeapTuple	tuple;	ResultRelInfo *resultRelInfo;	Relation	resultRelationDesc;	HTSU_Result result;	ItemPointerData update_ctid;	TransactionId update_xmax;	/*	 * abort the operation if not running transactions	 */	if (IsBootstrapProcessingMode())		elog(ERROR, "cannot UPDATE during bootstrap");	/*	 * get the heap tuple out of the tuple table slot, making sure we have a	 * writable copy	 */	tuple = ExecMaterializeSlot(slot);	/*	 * get information on the (current) result relation	 */	resultRelInfo = estate->es_result_relation_info;	resultRelationDesc = resultRelInfo->ri_RelationDesc;	/* BEFORE ROW UPDATE Triggers */	if (resultRelInfo->ri_TrigDesc &&		resultRelInfo->ri_TrigDesc->n_before_row[TRIGGER_EVENT_UPDATE] > 0)	{		HeapTuple	newtuple;		newtuple = ExecBRUpdateTriggers(estate, resultRelInfo,										tupleid, tuple,										estate->es_snapshot->curcid);		if (newtuple == NULL)	/* "do nothing" */			return;		if (newtuple != tuple)	/* modified by Trigger(s) */		{			/*			 * Put the modified tuple into a slot for convenience of routines			 * below.  We assume the tuple was allocated in per-tuple memory			 * context, and therefore will go away by itself. The tuple table			 * slot should not try to clear it.			 */			TupleTableSlot *newslot = estate->es_trig_tuple_slot;			if (newslot->tts_tupleDescriptor != slot->tts_tupleDescriptor)				ExecSetSlotDescriptor(newslot,									  slot->tts_tupleDescriptor,									  false);			ExecStoreTuple(newtuple, newslot, InvalidBuffer, false);			slot = newslot;			tuple = newtuple;		}	}	/*	 * Check the constraints of the tuple	 *	 * If we generate a new candidate tuple after EvalPlanQual testing, we	 * must loop back here and recheck constraints.  (We don't need to redo	 * triggers, however.  If there are any BEFORE triggers then trigger.c	 * will have done heap_lock_tuple to lock the correct tuple, so there's no	 * need to do them again.)	 */lreplace:;	if (resultRelationDesc->rd_att->constr)		ExecConstraints(resultRelInfo, slot, estate);	/*	 * replace the heap tuple	 *	 * Note: if es_crosscheck_snapshot isn't InvalidSnapshot, we check that	 * the row to be updated is visible to that snapshot, and throw a can't-	 * serialize error if not.	This is a special-case behavior needed for	 * referential integrity updates in serializable transactions.	 */	result = heap_update(resultRelationDesc, tupleid, tuple,						 &update_ctid, &update_xmax,						 estate->es_snapshot->curcid,						 estate->es_crosscheck_snapshot,						 true /* wait for commit */ );	switch (result)	{		case HeapTupleSelfUpdated:			/* already deleted by self; nothing to do */			return;		case HeapTupleMayBeUpdated:			break;		case HeapTupleUpdated:			if (IsXactIsoLevelSerializable)				ereport(ERROR,						(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),						 errmsg("could not serialize access due to concurrent update")));			else if (!ItemPointerEquals(tupleid, &update_ctid))			{				TupleTableSlot *epqslot;				epqslot = EvalPlanQual(estate,									   resultRelInfo->ri_RangeTableIndex,									   &update_ctid,									   update_xmax,									   estate->es_snapshot->curcid);				if (!TupIsNull(epqslot))				{					*tupleid = update_ctid;					slot = ExecFilterJunk(estate->es_junkFilter, epqslot);					tuple = ExecMaterializeSlot(slot);					goto lreplace;				}			}			/* tuple already deleted; nothing to do */			return;		default:			elog(ERROR, "unrecognized heap_update status: %u", result);			return;	}	IncrReplaced();	(estate->es_processed)++;	/*	 * Note: instead of having to update the old index tuples associated with	 * the heap tuple, all we do is form and insert new index tuples. This is	 * because UPDATEs are actually DELETEs and INSERTs, and index tuple	 * deletion is done automagically by the vacuum daemon. All we do is	 * insert new index tuples.  -cim 9/27/89	 */	/*	 * insert index entries for tuple	 *	 * Note: heap_update returns the tid (location) of the new tuple in the	 * t_self field.	 */	if (resultRelInfo->ri_NumIndices > 0)		ExecInsertIndexTuples(slot, &(tuple->t_self), estate, false);	/* AFTER ROW UPDATE Triggers */	ExecARUpdateTriggers(estate, resultRelInfo, tupleid, tuple);}static const char *ExecRelCheck(ResultRelInfo *resultRelInfo,			 TupleTableSlot *slot, EState *estate){	Relation	rel = resultRelInfo->ri_RelationDesc;	int			ncheck = rel->rd_att->constr->num_check;	ConstrCheck *check = rel->rd_att->constr->check;	ExprContext *econtext;	MemoryContext oldContext;	List	   *qual;	int			i;	/*	 * If first time through for this result relation, build expression	 * nodetrees for rel's constraint expressions.  Keep them in the per-query	 * memory context so they'll survive throughout the query.	 */	if (resultRelInfo->ri_ConstraintExprs == NULL)	{		oldContext = MemoryContextSwitchTo(estate->es_query_cxt);		resultRelInfo->ri_ConstraintExprs =			(List **) palloc(ncheck * sizeof(List *));		for (i = 0; i < ncheck; i++)		{			/* ExecQual wants implicit-AND form */			qual = make_ands_implicit(stringToNode(check[i].ccbin));			resultRelInfo->ri_ConstraintExprs[i] = (List *)				ExecPrepareExpr((Expr *) qual, estate);		}		MemoryContextSwitchTo(oldContext);	}	/*	 * We will use the EState's per-tuple context for evaluating constraint	 * expressions (creating it if it's not already there).	 */	econtext = GetPerTupleExprContext(estate);	/* Arrange for econtext's scan tuple to be the tuple under test */	econtext->ecxt_scantuple = slot;	/* And evaluate the constraints */	for (i = 0; i < ncheck; i++)	{		qual = resultRelInfo->ri_ConstraintExprs[i];		/*		 * NOTE: SQL92 specifies that a NULL result from a constraint		 * expression is not to be treated as a failure.  Therefore, tell		 * ExecQual to return TRUE for NULL.		 */		if (!ExecQual(qual, econtext, true))			return check[i].ccname;	}	/* NULL result means no error */	return NULL;}voidExecConstraints(ResultRelInfo *resultRelInfo,				TupleTableSlot *slot, EState *estate){	Relation	rel = resultRelInfo->ri_RelationDesc;	TupleConstr *constr = rel->rd_att->constr;	Assert(constr);	if (constr->has_not_null)	{		int			natts = rel->rd_att->natts;		int			attrChk;		for (attrChk = 1; attrChk <= natts; attrChk++)		{			if (rel->rd_att->attrs[attrChk - 1]->attnotnull &&				slot_attisnull(slot, attrChk))				ereport(ERROR,						(errcode(ERRCODE_NOT_NULL_VIOLATION),						 errmsg("null value in column \"%s\" violates not-null constraint",						NameStr(rel->rd_att->attrs[attrChk - 1]->attname))));		}	}	if (constr->num_check > 0)	{		const char *failed;		if ((failed = ExecRelCheck(resultRelInfo, slot, estate)) != NULL)			ereport(ERROR,					(errcode(ERRCODE_CHECK_VIOLATION),					 errmsg("new row for relation \"%s\" violates check constraint \"%s\"",							RelationGetRelationName(rel), failed)));	}}/* * Check a modified tuple to see if we want to process its updated version * under READ COMMITTED rules. * * See backend/executor/README for some info about how this works. * *	estate - executor state data *	rti - rangetable index of table containing tuple *	*tid - t_ctid from the outdated tuple (ie, next updated version) *	priorXmax - t_xmax from the outdated tuple *	curCid - command ID of current command of my transaction

⌨️ 快捷键说明

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