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

📄 execmain.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 4 页
字号:
			while (resultRelations != NIL)			{				initResultRelInfo(resultRelInfo,								  lfirsti(resultRelations),								  rangeTable,								  operation);				resultRelInfo++;				resultRelations = lnext(resultRelations);			}		}		else		{			/*			 * Single result relation identified by			 * parseTree->resultRelation			 */			numResultRelations = 1;			resultRelInfos = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));			initResultRelInfo(resultRelInfos,							  parseTree->resultRelation,							  rangeTable,							  operation);		}		estate->es_result_relations = resultRelInfos;		estate->es_num_result_relations = numResultRelations;		/* Initialize to first or only result rel */		estate->es_result_relation_info = resultRelInfos;	}	else	{		/*		 * if no result relation, then set state appropriately		 */		estate->es_result_relations = NULL;		estate->es_num_result_relations = 0;		estate->es_result_relation_info = NULL;	}	/*	 * Detect whether we're doing SELECT INTO.  If so, set the force_oids	 * flag appropriately so that the plan tree will be initialized with	 * the correct tuple descriptors.	 */	do_select_into = false;	if (operation == CMD_SELECT && parseTree->into != NULL)	{		do_select_into = true;		estate->es_select_into = true;		/*		 * For now, always create OIDs in SELECT INTO; this is for		 * backwards compatibility with pre-7.3 behavior.  Eventually we		 * might want to allow the user to choose.		 */		estate->es_into_oids = true;	}	/*	 * Have to lock relations selected for update	 */	estate->es_rowMark = NIL;	if (parseTree->rowMarks != NIL)	{		List	   *l;		foreach(l, parseTree->rowMarks)		{			Index		rti = lfirsti(l);			Oid			relid = getrelid(rti, rangeTable);			Relation	relation;			execRowMark *erm;			relation = heap_open(relid, RowShareLock);			erm = (execRowMark *) palloc(sizeof(execRowMark));			erm->relation = relation;			erm->rti = rti;			snprintf(erm->resname, sizeof(erm->resname), "ctid%u", rti);			estate->es_rowMark = lappend(estate->es_rowMark, erm);		}	}	/*	 * initialize the executor "tuple" table.  We need slots for all the	 * plan nodes, plus possibly output slots for the junkfilter(s). At	 * this point we aren't sure if we need junkfilters, so just add slots	 * for them unconditionally.	 */	{		int			nSlots = ExecCountSlotsNode(plan);		if (parseTree->resultRelations != NIL)			nSlots += length(parseTree->resultRelations);		else			nSlots += 1;		estate->es_tupleTable = ExecCreateTupleTable(nSlots);	}	/* mark EvalPlanQual not active */	estate->es_topPlan = plan;	estate->es_evalPlanQual = NULL;	estate->es_evTupleNull = NULL;	estate->es_evTuple = NULL;	estate->es_useEvalPlan = false;	/*	 * initialize the private state information for all the nodes in the	 * query tree.	This opens files, allocates storage and leaves us	 * ready to start processing tuples.	 */	planstate = ExecInitNode(plan, estate);	/*	 * Get the tuple descriptor describing the type of tuples to return.	 * (this is especially important if we are creating a relation with	 * "SELECT INTO")	 */	tupType = ExecGetResultType(planstate);	/*	 * Initialize the junk filter if needed.  SELECT and INSERT queries	 * need a filter if there are any junk attrs in the tlist.	INSERT and	 * SELECT INTO also need a filter if the plan may return raw disk tuples	 * (else heap_insert will be scribbling on the source relation!).	 * UPDATE and DELETE always need a filter, since there's always a junk	 * 'ctid' attribute present --- no need to look first.	 */	{		bool		junk_filter_needed = false;		List	   *tlist;		switch (operation)		{			case CMD_SELECT:			case CMD_INSERT:				foreach(tlist, plan->targetlist)				{					TargetEntry *tle = (TargetEntry *) lfirst(tlist);					if (tle->resdom->resjunk)					{						junk_filter_needed = true;						break;					}				}				if (!junk_filter_needed &&					(operation == CMD_INSERT || do_select_into) &&					ExecMayReturnRawTuples(planstate))					junk_filter_needed = true;				break;			case CMD_UPDATE:			case CMD_DELETE:				junk_filter_needed = true;				break;			default:				break;		}		if (junk_filter_needed)		{			/*			 * If there are multiple result relations, each one needs its			 * own junk filter.  Note this is only possible for			 * UPDATE/DELETE, so we can't be fooled by some needing a			 * filter and some not.			 */			if (parseTree->resultRelations != NIL)			{				PlanState **appendplans;				int			as_nplans;				ResultRelInfo *resultRelInfo;				int			i;				/* Top plan had better be an Append here. */				Assert(IsA(plan, Append));				Assert(((Append *) plan)->isTarget);				Assert(IsA(planstate, AppendState));				appendplans = ((AppendState *) planstate)->appendplans;				as_nplans = ((AppendState *) planstate)->as_nplans;				Assert(as_nplans == estate->es_num_result_relations);				resultRelInfo = estate->es_result_relations;				for (i = 0; i < as_nplans; i++)				{					PlanState  *subplan = appendplans[i];					JunkFilter *j;					j = ExecInitJunkFilter(subplan->plan->targetlist,										   ExecGetResultType(subplan),							  ExecAllocTableSlot(estate->es_tupleTable));					resultRelInfo->ri_junkFilter = j;					resultRelInfo++;				}				/*				 * Set active junkfilter too; at this point ExecInitAppend				 * has already selected an active result relation...				 */				estate->es_junkFilter =					estate->es_result_relation_info->ri_junkFilter;			}			else			{				/* Normal case with just one JunkFilter */				JunkFilter *j;				j = ExecInitJunkFilter(planstate->plan->targetlist,									   tupType,							  ExecAllocTableSlot(estate->es_tupleTable));				estate->es_junkFilter = j;				if (estate->es_result_relation_info)					estate->es_result_relation_info->ri_junkFilter = j;				/* For SELECT, want to return the cleaned tuple type */				if (operation == CMD_SELECT)					tupType = j->jf_cleanTupType;			}		}		else			estate->es_junkFilter = NULL;	}	/*	 * If doing SELECT INTO, initialize the "into" relation.  We must wait	 * till now so we have the "clean" result tuple type to create the new	 * table from.	 *	 * If EXPLAIN, skip creating the "into" relation.	 */	intoRelationDesc = (Relation) NULL;	if (do_select_into && !explainOnly)	{		char	   *intoName;		Oid			namespaceId;		AclResult	aclresult;		Oid			intoRelationId;		TupleDesc	tupdesc;		/*		 * find namespace to create in, check permissions		 */		intoName = parseTree->into->relname;		namespaceId = RangeVarGetCreationNamespace(parseTree->into);		aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),										  ACL_CREATE);		if (aclresult != ACLCHECK_OK)			aclcheck_error(aclresult, ACL_KIND_NAMESPACE,						   get_namespace_name(namespaceId));		/*		 * have to copy tupType to get rid of constraints		 */		tupdesc = CreateTupleDescCopy(tupType);		intoRelationId = heap_create_with_catalog(intoName,												  namespaceId,												  tupdesc,												  RELKIND_RELATION,												  false,												  ONCOMMIT_NOOP,												  allowSystemTableMods);		FreeTupleDesc(tupdesc);		/*		 * Advance command counter so that the newly-created relation's		 * catalog tuples will be visible to heap_open.		 */		CommandCounterIncrement();		/*		 * If necessary, create a TOAST table for the into relation. Note		 * that AlterTableCreateToastTable ends with		 * CommandCounterIncrement(), so that the TOAST table will be		 * visible for insertion.		 */		AlterTableCreateToastTable(intoRelationId, true);		/*		 * And open the constructed table for writing.		 */		intoRelationDesc = heap_open(intoRelationId, AccessExclusiveLock);	}	estate->es_into_relation_descriptor = intoRelationDesc;	queryDesc->tupDesc = tupType;	queryDesc->planstate = planstate;}/* * Initialize ResultRelInfo data for one result relation */static voidinitResultRelInfo(ResultRelInfo *resultRelInfo,				  Index resultRelationIndex,				  List *rangeTable,				  CmdType operation){	Oid			resultRelationOid;	Relation	resultRelationDesc;	resultRelationOid = getrelid(resultRelationIndex, rangeTable);	resultRelationDesc = heap_open(resultRelationOid, RowExclusiveLock);	switch (resultRelationDesc->rd_rel->relkind)	{		case RELKIND_SEQUENCE:			ereport(ERROR,					(errcode(ERRCODE_WRONG_OBJECT_TYPE),					 errmsg("cannot change sequence \"%s\"",						  RelationGetRelationName(resultRelationDesc))));			break;		case RELKIND_TOASTVALUE:			ereport(ERROR,					(errcode(ERRCODE_WRONG_OBJECT_TYPE),					 errmsg("cannot change TOAST relation \"%s\"",						  RelationGetRelationName(resultRelationDesc))));			break;		case RELKIND_VIEW:			ereport(ERROR,					(errcode(ERRCODE_WRONG_OBJECT_TYPE),					 errmsg("cannot change view \"%s\"",						  RelationGetRelationName(resultRelationDesc))));			break;	}	MemSet(resultRelInfo, 0, sizeof(ResultRelInfo));	resultRelInfo->type = T_ResultRelInfo;	resultRelInfo->ri_RangeTableIndex = resultRelationIndex;	resultRelInfo->ri_RelationDesc = resultRelationDesc;	resultRelInfo->ri_NumIndices = 0;	resultRelInfo->ri_IndexRelationDescs = NULL;	resultRelInfo->ri_IndexRelationInfo = NULL;	/* make a copy so as not to depend on relcache info not changing... */	resultRelInfo->ri_TrigDesc = CopyTriggerDesc(resultRelationDesc->trigdesc);	resultRelInfo->ri_TrigFunctions = NULL;	resultRelInfo->ri_ConstraintExprs = NULL;	resultRelInfo->ri_junkFilter = NULL;	/*	 * If there are indices on the result relation, open them and save	 * descriptors in the result relation info, so that we can add new	 * index entries for the tuples we add/update.	We need not do this	 * for a DELETE, however, since deletion doesn't affect indexes.	 */	if (resultRelationDesc->rd_rel->relhasindex &&		operation != CMD_DELETE)		ExecOpenIndices(resultRelInfo);}/* *		ExecContextForcesOids * * This is pretty grotty: when doing INSERT, UPDATE, or SELECT INTO, * we need to ensure that result tuples have space for an OID iff they are * going to be stored into a relation that has OIDs.  In other contexts * we are free to choose whether to leave space for OIDs in result tuples * (we generally don't want to, but we do if a physical-tlist optimization * is possible).  This routine checks the plan context and returns TRUE if the * choice is forced, FALSE if the choice is not forced.  In the TRUE case, * *hasoids is set to the required value. * * One reason this is ugly is that all plan nodes in the plan tree will emit * tuples with space for an OID, though we really only need the topmost node * to do so.  However, node types like Sort don't project new tuples but just * return their inputs, and in those cases the requirement propagates down * to the input node.  Eventually we might make this code smart enough to * recognize how far down the requirement really goes, but for now we just * make all plan nodes do the same thing if the top level forces the choice. * * 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;	List	   *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)		heap_close(estate->es_into_relation_descriptor, NoLock);	/*	 * close any relations selected FOR UPDATE, again keeping locks	 */	foreach(l, estate->es_rowMark)	{		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 (;;)	{

⌨️ 快捷键说明

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