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

📄 execmain.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
	TupleDesc	tupType;	/*	 * Do permissions checks.  It's sufficient to examine the query's top	 * rangetable here --- subplan RTEs will be checked during	 * ExecInitSubPlan().	 */	ExecCheckRTPerms(parseTree->rtable);	/*	 * get information from query descriptor	 */	rangeTable = parseTree->rtable;	/*	 * initialize the node's execution state	 */	estate->es_range_table = rangeTable;	/*	 * if there is a result relation, initialize result relation stuff	 */	if (parseTree->resultRelation != 0 && operation != CMD_SELECT)	{		List	   *resultRelations = parseTree->resultRelations;		int			numResultRelations;		ResultRelInfo *resultRelInfos;		if (resultRelations != NIL)		{			/*			 * Multiple result relations (due to inheritance)			 * parseTree->resultRelations identifies them all			 */			ResultRelInfo *resultRelInfo;			ListCell   *l;			numResultRelations = list_length(resultRelations);			resultRelInfos = (ResultRelInfo *)				palloc(numResultRelations * sizeof(ResultRelInfo));			resultRelInfo = resultRelInfos;			foreach(l, resultRelations)			{				initResultRelInfo(resultRelInfo,								  lfirst_int(l),								  rangeTable,								  operation,								  estate->es_instrument);				resultRelInfo++;			}		}		else		{			/*			 * Single result relation identified by parseTree->resultRelation			 */			numResultRelations = 1;			resultRelInfos = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));			initResultRelInfo(resultRelInfos,							  parseTree->resultRelation,							  rangeTable,							  operation,							  estate->es_instrument);		}		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 es_into_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;		estate->es_into_oids = parseTree->intoHasOids;	}	/*	 * Have to lock relations selected FOR UPDATE/FOR SHARE	 */	estate->es_rowMarks = NIL;	estate->es_forUpdate = parseTree->forUpdate;	estate->es_rowNoWait = parseTree->rowNoWait;	if (parseTree->rowMarks != NIL)	{		ListCell   *l;		foreach(l, parseTree->rowMarks)		{			Index		rti = lfirst_int(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_rowMarks = lappend(estate->es_rowMarks, 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.  Also, if it's not a SELECT, set up a slot for use for	 * trigger output tuples.	 */	{		int			nSlots = ExecCountSlotsNode(plan);		if (parseTree->resultRelations != NIL)			nSlots += list_length(parseTree->resultRelations);		else			nSlots += 1;		if (operation != CMD_SELECT)			nSlots++;		estate->es_tupleTable = ExecCreateTupleTable(nSlots);		if (operation != CMD_SELECT)			estate->es_trig_tuple_slot =				ExecAllocTableSlot(estate->es_tupleTable);	}	/* 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;		ListCell   *tlist;		switch (operation)		{			case CMD_SELECT:			case CMD_INSERT:				foreach(tlist, plan->targetlist)				{					TargetEntry *tle = (TargetEntry *) lfirst(tlist);					if (tle->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,							resultRelInfo->ri_RelationDesc->rd_att->tdhasoid,								  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->tdhasoid,								  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 = NULL;	if (do_select_into && !explainOnly)	{		char	   *intoName;		Oid			namespaceId;		Oid			tablespaceId;		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));		tablespaceId = GetDefaultTablespace();		if (OidIsValid(tablespaceId)) {			aclresult = pg_tablespace_aclcheck(tablespaceId, GetUserId(),											   ACL_CREATE);			if (aclresult != ACLCHECK_OK)				aclcheck_error(aclresult, ACL_KIND_TABLESPACE,							   get_tablespace_name(tablespaceId));		}		/*		 * have to copy tupType to get rid of constraints		 */		tupdesc = CreateTupleDescCopy(tupType);		intoRelationId = heap_create_with_catalog(intoName,												  namespaceId,												  tablespaceId,												  InvalidOid,												  GetUserId(),												  tupdesc,												  RELKIND_RELATION,												  false,												  true,												  0,												  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);		/* use_wal off requires rd_targblock be initially invalid */		Assert(intoRelationDesc->rd_targblock == InvalidBlockNumber);		/*		 * We can skip WAL-logging the insertions, unless PITR is in use.		 *		 * Note that for a non-temp INTO table, this is safe only because we		 * know that the catalog changes above will have been WAL-logged, and		 * so RecordTransactionCommit will think it needs to WAL-log the		 * eventual transaction commit.  Else the commit might be lost, even		 * though all the data is safely fsync'd ...		 */		estate->es_into_relation_use_wal = XLogArchivingActive();	}	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,				  bool doInstrument){	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);	if (resultRelInfo->ri_TrigDesc)	{		int			n = resultRelInfo->ri_TrigDesc->numtriggers;		resultRelInfo->ri_TrigFunctions = (FmgrInfo *)			palloc0(n * sizeof(FmgrInfo));		if (doInstrument)			resultRelInfo->ri_TrigInstrument = InstrAlloc(n);		else			resultRelInfo->ri_TrigInstrument = NULL;	}	else	{		resultRelInfo->ri_TrigFunctions = NULL;		resultRelInfo->ri_TrigInstrument = 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.

⌨️ 快捷键说明

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