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

📄 execmain.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 4 页
字号:
		/* Reset the per-output-tuple exprcontext */		ResetPerTupleExprContext(estate);		/*		 * Execute the plan and obtain a tuple		 */lnext:	;		if (estate->es_useEvalPlan)		{			slot = EvalPlanQualNext(estate);			if (TupIsNull(slot))				slot = ExecProcNode(planstate);		}		else			slot = ExecProcNode(planstate);		/*		 * if the tuple is null, then we assume there is nothing more to		 * process so we just return null...		 */		if (TupIsNull(slot))		{			result = NULL;			break;		}		/*		 * if we have a junk filter, then project a new tuple with the		 * junk removed.		 *		 * Store this new "clean" tuple in the junkfilter's resultSlot.		 * (Formerly, we stored it back over the "dirty" tuple, which is		 * WRONG because that tuple slot has the wrong descriptor.)		 *		 * Also, extract all the junk information we need.		 */		if ((junkfilter = estate->es_junkFilter) != (JunkFilter *) NULL)		{			Datum		datum;			HeapTuple	newTuple;			bool		isNull;			/*			 * extract the 'ctid' junk attribute.			 */			if (operation == CMD_UPDATE || operation == CMD_DELETE)			{				if (!ExecGetJunkAttribute(junkfilter,										  slot,										  "ctid",										  &datum,										  &isNull))					elog(ERROR, "could not find junk ctid column");				/* shouldn't ever get a null result... */				if (isNull)					elog(ERROR, "ctid is NULL");				tupleid = (ItemPointer) DatumGetPointer(datum);				tuple_ctid = *tupleid;	/* make sure we don't free the										 * ctid!! */				tupleid = &tuple_ctid;			}			else if (estate->es_rowMark != NIL)			{				List	   *l;		lmark:	;				foreach(l, estate->es_rowMark)				{					execRowMark *erm = lfirst(l);					Buffer		buffer;					HeapTupleData tuple;					TupleTableSlot *newSlot;					int			test;					if (!ExecGetJunkAttribute(junkfilter,											  slot,											  erm->resname,											  &datum,											  &isNull))						elog(ERROR, "could not find junk \"%s\" column",							 erm->resname);					/* shouldn't ever get a null result... */					if (isNull)						elog(ERROR, "\"%s\" is NULL", erm->resname);					tuple.t_self = *((ItemPointer) DatumGetPointer(datum));					test = heap_mark4update(erm->relation, &tuple, &buffer,											estate->es_snapshot->curcid);					ReleaseBuffer(buffer);					switch (test)					{						case HeapTupleSelfUpdated:							/* treat it as deleted; do not process */							goto lnext;						case HeapTupleMayBeUpdated:							break;						case HeapTupleUpdated:							if (XactIsoLevel == XACT_SERIALIZABLE)								ereport(ERROR,										(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),										 errmsg("could not serialize access due to concurrent update")));							if (!(ItemPointerEquals(&(tuple.t_self),								  (ItemPointer) DatumGetPointer(datum))))							{								newSlot = EvalPlanQual(estate, erm->rti, &(tuple.t_self));								if (!(TupIsNull(newSlot)))								{									slot = newSlot;									estate->es_useEvalPlan = true;									goto lmark;								}							}							/*							 * if tuple was deleted or PlanQual failed for							 * updated tuple - we must not return this							 * tuple!							 */							goto lnext;						default:							elog(ERROR, "unrecognized heap_mark4update status: %u",								 test);							return (NULL);					}				}			}			/*			 * Finally create a new "clean" tuple with all junk attributes			 * removed			 */			newTuple = ExecRemoveJunk(junkfilter, slot);			slot = ExecStoreTuple(newTuple,		/* tuple to store */								  junkfilter->jf_resultSlot,	/* dest slot */								  InvalidBuffer,		/* this tuple has no														 * buffer */								  true);		/* tuple should be pfreed */		}		/*		 * now that we have a tuple, do the appropriate thing with it..		 * either return it to the user, add it to a relation someplace,		 * delete it from a relation, or modify some of its attributes.		 */		switch (operation)		{			case CMD_SELECT:				ExecSelect(slot,	/* slot containing tuple */						   dest,	/* destination's tuple-receiver obj */						   estate);				result = slot;				break;			case CMD_INSERT:				ExecInsert(slot, tupleid, estate);				result = NULL;				break;			case CMD_DELETE:				ExecDelete(slot, tupleid, estate);				result = NULL;				break;			case CMD_UPDATE:				ExecUpdate(slot, tupleid, estate);				result = NULL;				break;			default:				elog(ERROR, "unrecognized operation code: %d",					 (int) operation);				result = NULL;				break;		}		/*		 * check our tuple count.. if we've processed the proper number		 * then quit, else loop again and process more tuples.	Zero		 * numberTuples means no limit.		 */		current_tuple_count++;		if (numberTuples && numberTuples == current_tuple_count)			break;	}	/*	 * Process AFTER EACH STATEMENT triggers	 */	switch (operation)	{		case CMD_UPDATE:			ExecASUpdateTriggers(estate, estate->es_result_relation_info);			break;		case CMD_DELETE:			ExecASDeleteTriggers(estate, estate->es_result_relation_info);			break;		case CMD_INSERT:			ExecASInsertTriggers(estate, estate->es_result_relation_info);			break;		default:			/* do nothing */			break;	}	/*	 * here, result is either a slot containing a tuple in the case of a	 * SELECT or NULL otherwise.	 */	return result;}/* ---------------------------------------------------------------- *		ExecSelect * *		SELECTs are easy.. we just pass the tuple to the appropriate *		print function.  The only complexity is when we do a *		"SELECT INTO", in which case we insert the tuple into *		the appropriate relation (note: this is a newly created relation *		so we don't need to worry about indices or locks.) * ---------------------------------------------------------------- */static voidExecSelect(TupleTableSlot *slot,		   DestReceiver *dest,		   EState *estate){	HeapTuple	tuple;	TupleDesc	attrtype;	/*	 * get the heap tuple out of the tuple table slot	 */	tuple = slot->val;	attrtype = slot->ttc_tupleDescriptor;	/*	 * insert the tuple into the "into relation"	 *	 * XXX this probably ought to be replaced by a separate destination	 */	if (estate->es_into_relation_descriptor != NULL)	{		heap_insert(estate->es_into_relation_descriptor, tuple,					estate->es_snapshot->curcid);		IncrAppended();	}	/*	 * send the tuple to the destination	 */	(*dest->receiveTuple) (tuple, attrtype, dest);	IncrRetrieved();	(estate->es_processed)++;}/* ---------------------------------------------------------------- *		ExecInsert * *		INSERTs are trickier.. we have to insert the tuple into *		the base relation and insert appropriate tuples into the *		index relations. * ---------------------------------------------------------------- */static voidExecInsert(TupleTableSlot *slot,		   ItemPointer tupleid,		   EState *estate){	HeapTuple	tuple;	ResultRelInfo *resultRelInfo;	Relation	resultRelationDesc;	int			numIndices;	Oid			newId;	/*	 * get the heap tuple out of the tuple table slot	 */	tuple = slot->val;	/*	 * 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) */		{			/*			 * Insert modified tuple into tuple table slot, replacing the			 * original.  We assume that it was allocated in per-tuple			 * memory context, and therefore will go away by itself. The			 * tuple table slot should not try to clear it.			 */			ExecStoreTuple(newtuple, slot, InvalidBuffer, false);			tuple = newtuple;		}	}	/*	 * Check the constraints of the tuple	 */	if (resultRelationDesc->rd_att->constr)		ExecConstraints(resultRelInfo, slot, estate);	/*	 * insert the tuple	 */	newId = heap_insert(resultRelationDesc, tuple,						estate->es_snapshot->curcid);	IncrAppended();	(estate->es_processed)++;	estate->es_lastoid = newId;	setLastTid(&(tuple->t_self));	/*	 * process indices	 *	 * Note: heap_insert adds a new tuple to a relation.  As a side effect,	 * the tupleid of the new tuple is placed in the new tuple's t_ctid	 * field.	 */	numIndices = resultRelInfo->ri_NumIndices;	if (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;	ItemPointerData ctid;	int			result;	/*	 * 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	 */ldelete:;	result = heap_delete(resultRelationDesc, tupleid,						 &ctid,						 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 (XactIsoLevel == XACT_SERIALIZABLE)				ereport(ERROR,						(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),						 errmsg("could not serialize access due to concurrent update")));			else if (!(ItemPointerEquals(tupleid, &ctid)))			{				TupleTableSlot *epqslot = EvalPlanQual(estate,							   resultRelInfo->ri_RangeTableIndex, &ctid);				if (!TupIsNull(epqslot))				{					*tupleid = 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;	ItemPointerData ctid;	int			result;	int			numIndices;	/*	 * 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	 */	tuple = slot->val;	/*	 * 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) */		{			/*			 * Insert modified tuple into tuple table slot, replacing the			 * original.  We assume that it was allocated in per-tuple			 * memory context, and therefore will go away by itself. The			 * tuple table slot should not try to clear it.			 */			ExecStoreTuple(newtuple, slot, InvalidBuffer, false);			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 mark4update 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	 */	result = heap_update(resultRelationDesc, tupleid, tuple,						 &ctid,						 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 (XactIsoLevel == XACT_SERIALIZABLE)				ereport(ERROR,						(errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),						 errmsg("could not serialize access due to concurrent update")));			else if (!(ItemPointerEquals(tupleid, &ctid)))

⌨️ 快捷键说明

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