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

📄 execmain.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
 * * We assume that estate->es_result_relation_info is already set up to * describe the target relation.  Note that in an UPDATE that spans an * inheritance tree, some of the target relations may have OIDs and some not. * We have to make the decisions on a per-relation basis as we initialize * each of the child plans of the topmost Append plan. * * SELECT INTO is even uglier, because we don't have the INTO relation's * descriptor available when this code runs; we have to look aside at a * flag set by InitPlan(). */boolExecContextForcesOids(PlanState *planstate, bool *hasoids){	if (planstate->state->es_select_into)	{		*hasoids = planstate->state->es_into_oids;		return true;	}	else	{		ResultRelInfo *ri = planstate->state->es_result_relation_info;		if (ri != NULL)		{			Relation	rel = ri->ri_RelationDesc;			if (rel != NULL)			{				*hasoids = rel->rd_rel->relhasoids;				return true;			}		}	}	return false;}/* ---------------------------------------------------------------- *		ExecEndPlan * *		Cleans up the query plan -- closes files and frees up storage * * NOTE: we are no longer very worried about freeing storage per se * in this code; FreeExecutorState should be guaranteed to release all * memory that needs to be released.  What we are worried about doing * is closing relations and dropping buffer pins.  Thus, for example, * tuple tables must be cleared or dropped to ensure pins are released. * ---------------------------------------------------------------- */voidExecEndPlan(PlanState *planstate, EState *estate){	ResultRelInfo *resultRelInfo;	int			i;	ListCell   *l;	/*	 * shut down any PlanQual processing we were doing	 */	if (estate->es_evalPlanQual != NULL)		EndEvalPlanQual(estate);	/*	 * shut down the node-type-specific query processing	 */	ExecEndNode(planstate);	/*	 * destroy the executor "tuple" table.	 */	ExecDropTupleTable(estate->es_tupleTable, true);	estate->es_tupleTable = NULL;	/*	 * close the result relation(s) if any, but hold locks until xact commit.	 */	resultRelInfo = estate->es_result_relations;	for (i = estate->es_num_result_relations; i > 0; i--)	{		/* Close indices and then the relation itself */		ExecCloseIndices(resultRelInfo);		heap_close(resultRelInfo->ri_RelationDesc, NoLock);		resultRelInfo++;	}	/*	 * close the "into" relation if necessary, again keeping lock	 */	if (estate->es_into_relation_descriptor != NULL)	{		/*		 * If we skipped using WAL, and it's not a temp relation, we must		 * force the relation down to disk before it's safe to commit the		 * transaction.  This requires forcing out any dirty buffers and then		 * doing a forced fsync.		 */		if (!estate->es_into_relation_use_wal &&			!estate->es_into_relation_descriptor->rd_istemp)		{			FlushRelationBuffers(estate->es_into_relation_descriptor);			smgrimmedsync(estate->es_into_relation_descriptor->rd_smgr);		}		heap_close(estate->es_into_relation_descriptor, NoLock);	}	/*	 * close any relations selected FOR UPDATE/FOR SHARE, again keeping locks	 */	foreach(l, estate->es_rowMarks)	{		execRowMark *erm = lfirst(l);		heap_close(erm->relation, NoLock);	}}/* ---------------------------------------------------------------- *		ExecutePlan * *		processes the query plan to retrieve 'numberTuples' tuples in the *		direction specified. * *		Retrieves all tuples if numberTuples is 0 * *		result is either a slot containing the last tuple in the case *		of a SELECT or NULL otherwise. * * Note: the ctid attribute is a 'junk' attribute that is removed before the * user can see it * ---------------------------------------------------------------- */static TupleTableSlot *ExecutePlan(EState *estate,			PlanState *planstate,			CmdType operation,			long numberTuples,			ScanDirection direction,			DestReceiver *dest){	JunkFilter *junkfilter;	TupleTableSlot *slot;	ItemPointer tupleid = NULL;	ItemPointerData tuple_ctid;	long		current_tuple_count;	TupleTableSlot *result;	/*	 * initialize local variables	 */	slot = NULL;	current_tuple_count = 0;	result = NULL;	/*	 * Set the direction.	 */	estate->es_direction = direction;	/*	 * Process BEFORE EACH STATEMENT triggers	 */	switch (operation)	{		case CMD_UPDATE:			ExecBSUpdateTriggers(estate, estate->es_result_relation_info);			break;		case CMD_DELETE:			ExecBSDeleteTriggers(estate, estate->es_result_relation_info);			break;		case CMD_INSERT:			ExecBSInsertTriggers(estate, estate->es_result_relation_info);			break;		default:			/* do nothing */			break;	}	/*	 * Loop until we've processed the proper number of tuples from the plan.	 */	for (;;)	{		/* 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) != NULL)		{			Datum		datum;			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;			}			/*			 * Process any FOR UPDATE or FOR SHARE locking requested.			 */			else if (estate->es_rowMarks != NIL)			{				ListCell   *l;		lmark:	;				foreach(l, estate->es_rowMarks)				{					execRowMark *erm = lfirst(l);					HeapTupleData tuple;					Buffer		buffer;					ItemPointerData update_ctid;					TransactionId update_xmax;					TupleTableSlot *newSlot;					LockTupleMode lockmode;					HTSU_Result 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));					if (estate->es_forUpdate)						lockmode = LockTupleExclusive;					else						lockmode = LockTupleShared;					test = heap_lock_tuple(erm->relation, &tuple, &buffer,										   &update_ctid, &update_xmax,										   estate->es_snapshot->curcid,										   lockmode, estate->es_rowNoWait);					ReleaseBuffer(buffer);					switch (test)					{						case HeapTupleSelfUpdated:							/* treat it as deleted; do not process */							goto lnext;						case HeapTupleMayBeUpdated:							break;						case HeapTupleUpdated:							if (IsXactIsoLevelSerializable)								ereport(ERROR,								 (errcode(ERRCODE_T_R_SERIALIZATION_FAILURE),								  errmsg("could not serialize access due to concurrent update")));							if (!ItemPointerEquals(&update_ctid,												   &tuple.t_self))							{								/* updated, so look at updated version */								newSlot = EvalPlanQual(estate,													   erm->rti,													   &update_ctid,													   update_xmax,													   estate->es_snapshot->curcid);								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_lock_tuple status: %u",								 test);							return (NULL);					}				}			}			/*			 * Finally create a new "clean" tuple with all junk attributes			 * removed			 */			slot = ExecFilterJunk(junkfilter, slot);		}		/*		 * 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){	/*	 * 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)	{		HeapTuple	tuple;		tuple = ExecCopySlotTuple(slot);		heap_insert(estate->es_into_relation_descriptor, tuple,					estate->es_snapshot->curcid,					estate->es_into_relation_use_wal,					false);		/* never any point in using FSM */		/* we know there are no indexes to update */		heap_freetuple(tuple);		IncrAppended();	}	/*	 * send the tuple to the destination	 */	(*dest->receiveSlot) (slot, 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

⌨️ 快捷键说明

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