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

📄 execmain.c

📁 PostgreSQL7.4.6 for Linux
💻 C
📖 第 1 页 / 共 4 页
字号:
/*------------------------------------------------------------------------- * * execMain.c *	  top level executor interface routines * * INTERFACE ROUTINES *	ExecutorStart() *	ExecutorRun() *	ExecutorEnd() * *	The old ExecutorMain() has been replaced by ExecutorStart(), *	ExecutorRun() and ExecutorEnd() * *	These three procedures are the external interfaces to the executor. *	In each case, the query descriptor is required as an argument. * *	ExecutorStart() must be called at the beginning of execution of any *	query plan and ExecutorEnd() should always be called at the end of *	execution of a plan. * *	ExecutorRun accepts direction and count arguments that specify whether *	the plan is to be executed forwards, backwards, and for how many tuples. * * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.220.2.2 2004/03/02 18:56:28 tgl Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "catalog/heap.h"#include "catalog/namespace.h"#include "commands/tablecmds.h"#include "commands/trigger.h"#include "executor/execdebug.h"#include "executor/execdefs.h"#include "miscadmin.h"#include "optimizer/var.h"#include "parser/parsetree.h"#include "utils/acl.h"#include "utils/lsyscache.h"typedef struct execRowMark{	Relation	relation;	Index		rti;	char		resname[32];} execRowMark;typedef struct evalPlanQual{	Index		rti;	EState	   *estate;	PlanState  *planstate;	struct evalPlanQual *next;	/* stack of active PlanQual plans */	struct evalPlanQual *free;	/* list of free PlanQual plans */} evalPlanQual;/* decls for local routines only used within this module */static void InitPlan(QueryDesc *queryDesc, bool explainOnly);static void initResultRelInfo(ResultRelInfo *resultRelInfo,				  Index resultRelationIndex,				  List *rangeTable,				  CmdType operation);static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate,			CmdType operation,			long numberTuples,			ScanDirection direction,			DestReceiver *dest);static void ExecSelect(TupleTableSlot *slot,		   DestReceiver *dest,		   EState *estate);static void ExecInsert(TupleTableSlot *slot, ItemPointer tupleid,		   EState *estate);static void ExecDelete(TupleTableSlot *slot, ItemPointer tupleid,		   EState *estate);static void ExecUpdate(TupleTableSlot *slot, ItemPointer tupleid,		   EState *estate);static TupleTableSlot *EvalPlanQualNext(EState *estate);static void EndEvalPlanQual(EState *estate);static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation);static void ExecCheckXactReadOnly(Query *parsetree, CmdType operation);static void EvalPlanQualStart(evalPlanQual *epq, EState *estate,				  evalPlanQual *priorepq);static void EvalPlanQualStop(evalPlanQual *epq);/* end of local decls *//* ---------------------------------------------------------------- *		ExecutorStart * *		This routine must be called at the beginning of any execution of any *		query plan * * Takes a QueryDesc previously created by CreateQueryDesc (it's not real * clear why we bother to separate the two functions, but...).	The tupDesc * field of the QueryDesc is filled in to describe the tuples that will be * returned, and the internal fields (estate and planstate) are set up. * * If useCurrentSnapshot is true, run the query with the latest available * snapshot, instead of the normal QuerySnapshot.  Also, if it's an update * or delete query, check that the rows to be updated or deleted would be * visible to the normal QuerySnapshot.  (This is a special-case behavior * needed for referential integrity updates in serializable transactions. * We must check all currently-committed rows, but we want to throw a * can't-serialize error if any rows that would need updates would not be * visible under the normal serializable snapshot.) * * If explainOnly is true, we are not actually intending to run the plan, * only to set up for EXPLAIN; so skip unwanted side-effects. * * NB: the CurrentMemoryContext when this is called will become the parent * of the per-query context used for this Executor invocation. * ---------------------------------------------------------------- */voidExecutorStart(QueryDesc *queryDesc, bool useCurrentSnapshot, bool explainOnly){	EState	   *estate;	MemoryContext oldcontext;	/* sanity checks: queryDesc must not be started already */	Assert(queryDesc != NULL);	Assert(queryDesc->estate == NULL);	/*	 * If the transaction is read-only, we need to check if any writes are	 * planned to non-temporary tables.	 */	if (!explainOnly)		ExecCheckXactReadOnly(queryDesc->parsetree, queryDesc->operation);	/*	 * Build EState, switch into per-query memory context for startup.	 */	estate = CreateExecutorState();	queryDesc->estate = estate;	oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);	/*	 * Fill in parameters, if any, from queryDesc	 */	estate->es_param_list_info = queryDesc->params;	if (queryDesc->plantree->nParamExec > 0)		estate->es_param_exec_vals = (ParamExecData *)			palloc0(queryDesc->plantree->nParamExec * sizeof(ParamExecData));	estate->es_instrument = queryDesc->doInstrument;	/*	 * Make our own private copy of the current query snapshot data.	 *	 * This "freezes" our idea of which tuples are good and which are not for	 * the life of this query, even if it outlives the current command and	 * current snapshot.	 */	if (useCurrentSnapshot)	{		/* RI update/delete query --- must use an up-to-date snapshot */		estate->es_snapshot = CopyCurrentSnapshot();		/* crosscheck updates/deletes against transaction snapshot */		estate->es_crosscheck_snapshot = CopyQuerySnapshot();	}	else	{		/* normal query --- use query snapshot, no crosscheck */		estate->es_snapshot = CopyQuerySnapshot();		estate->es_crosscheck_snapshot = SnapshotAny;	}	/*	 * Initialize the plan state tree	 */	InitPlan(queryDesc, explainOnly);	MemoryContextSwitchTo(oldcontext);}/* ---------------------------------------------------------------- *		ExecutorRun * *		This is the main routine of the executor module. It accepts *		the query descriptor from the traffic cop and executes the *		query plan. * *		ExecutorStart must have been called already. * *		If direction is NoMovementScanDirection then nothing is done *		except to start up/shut down the destination.  Otherwise, *		we retrieve up to 'count' tuples in the specified direction. * *		Note: count = 0 is interpreted as no portal limit, i.e., run to *		completion. * * ---------------------------------------------------------------- */TupleTableSlot *ExecutorRun(QueryDesc *queryDesc,			ScanDirection direction, long count){	EState	   *estate;	CmdType		operation;	DestReceiver *dest;	TupleTableSlot *result;	MemoryContext oldcontext;	/* sanity checks */	Assert(queryDesc != NULL);	estate = queryDesc->estate;	Assert(estate != NULL);	/*	 * Switch into per-query memory context	 */	oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);	/*	 * extract information from the query descriptor and the query	 * feature.	 */	operation = queryDesc->operation;	dest = queryDesc->dest;	/*	 * startup tuple receiver	 */	estate->es_processed = 0;	estate->es_lastoid = InvalidOid;	(*dest->rStartup) (dest, operation, queryDesc->tupDesc);	/*	 * run plan	 */	if (direction == NoMovementScanDirection)		result = NULL;	else		result = ExecutePlan(estate,							 queryDesc->planstate,							 operation,							 count,							 direction,							 dest);	/*	 * shutdown receiver	 */	(*dest->rShutdown) (dest);	MemoryContextSwitchTo(oldcontext);	return result;}/* ---------------------------------------------------------------- *		ExecutorEnd * *		This routine must be called at the end of execution of any *		query plan * ---------------------------------------------------------------- */voidExecutorEnd(QueryDesc *queryDesc){	EState	   *estate;	MemoryContext oldcontext;	/* sanity checks */	Assert(queryDesc != NULL);	estate = queryDesc->estate;	Assert(estate != NULL);	/*	 * Switch into per-query memory context to run ExecEndPlan	 */	oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);	ExecEndPlan(queryDesc->planstate, estate);	/*	 * Must switch out of context before destroying it	 */	MemoryContextSwitchTo(oldcontext);	/*	 * Release EState and per-query memory context.  This should release	 * everything the executor has allocated.	 */	FreeExecutorState(estate);	/* Reset queryDesc fields that no longer point to anything */	queryDesc->tupDesc = NULL;	queryDesc->estate = NULL;	queryDesc->planstate = NULL;}/* ---------------------------------------------------------------- *		ExecutorRewind * *		This routine may be called on an open queryDesc to rewind it *		to the start. * ---------------------------------------------------------------- */voidExecutorRewind(QueryDesc *queryDesc){	EState	   *estate;	MemoryContext oldcontext;	/* sanity checks */	Assert(queryDesc != NULL);	estate = queryDesc->estate;	Assert(estate != NULL);	/* It's probably not sensible to rescan updating queries */	Assert(queryDesc->operation == CMD_SELECT);	/*	 * Switch into per-query memory context	 */	oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);	/*	 * rescan plan	 */	ExecReScan(queryDesc->planstate, NULL);	MemoryContextSwitchTo(oldcontext);}/* * ExecCheckRTPerms *		Check access permissions for all relations listed in a range table. */voidExecCheckRTPerms(List *rangeTable, CmdType operation){	List	   *lp;	foreach(lp, rangeTable)	{		RangeTblEntry *rte = lfirst(lp);		ExecCheckRTEPerms(rte, operation);	}}/* * ExecCheckRTEPerms *		Check access permissions for a single RTE. */static voidExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation){	Oid			relOid;	AclId		userid;	AclResult	aclcheck_result;	/*	 * If it's a subquery, recursively examine its rangetable.	 */	if (rte->rtekind == RTE_SUBQUERY)	{		ExecCheckRTPerms(rte->subquery->rtable, operation);		return;	}	/*	 * Otherwise, only plain-relation RTEs need to be checked here.	 * Function RTEs are checked by init_fcache when the function is	 * prepared for execution. Join and special RTEs need no checks.	 */	if (rte->rtekind != RTE_RELATION)		return;	relOid = rte->relid;	/*	 * userid to check as: current user unless we have a setuid	 * indication.	 *	 * Note: GetUserId() is presently fast enough that there's no harm in	 * calling it separately for each RTE.	If that stops being true, we	 * could call it once in ExecCheckRTPerms and pass the userid down	 * from there.	But for now, no need for the extra clutter.	 */	userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();#define CHECK(MODE)		pg_class_aclcheck(relOid, userid, MODE)	if (rte->checkForRead)	{		aclcheck_result = CHECK(ACL_SELECT);		if (aclcheck_result != ACLCHECK_OK)			aclcheck_error(aclcheck_result, ACL_KIND_CLASS,						   get_rel_name(relOid));	}	if (rte->checkForWrite)	{		/*		 * Note: write access in a SELECT context means SELECT FOR UPDATE.		 * Right now we don't distinguish that from true update as far as		 * permissions checks are concerned.		 */		switch (operation)		{			case CMD_INSERT:				aclcheck_result = CHECK(ACL_INSERT);				break;			case CMD_SELECT:			case CMD_UPDATE:				aclcheck_result = CHECK(ACL_UPDATE);				break;			case CMD_DELETE:				aclcheck_result = CHECK(ACL_DELETE);				break;			default:				elog(ERROR, "unrecognized operation code: %d",					 (int) operation);				aclcheck_result = ACLCHECK_OK;	/* keep compiler quiet */				break;		}		if (aclcheck_result != ACLCHECK_OK)			aclcheck_error(aclcheck_result, ACL_KIND_CLASS,						   get_rel_name(relOid));	}}static voidExecCheckXactReadOnly(Query *parsetree, CmdType operation){	if (!XactReadOnly)		return;	/* CREATE TABLE AS or SELECT INTO */	if (operation == CMD_SELECT && parsetree->into != NULL)		goto fail;	if (operation == CMD_DELETE || operation == CMD_INSERT		|| operation == CMD_UPDATE)	{		List	   *lp;		foreach(lp, parsetree->rtable)		{			RangeTblEntry *rte = lfirst(lp);			if (rte->rtekind != RTE_RELATION)				continue;			if (!rte->checkForWrite)				continue;			if (isTempNamespace(get_rel_namespace(rte->relid)))				continue;			goto fail;		}	}	return;fail:	ereport(ERROR,			(errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),			 errmsg("transaction is read-only")));}/* ---------------------------------------------------------------- *		InitPlan * *		Initializes the query plan: open files, allocate storage *		and start up the rule manager * ---------------------------------------------------------------- */static voidInitPlan(QueryDesc *queryDesc, bool explainOnly){	CmdType		operation = queryDesc->operation;	Query	   *parseTree = queryDesc->parsetree;	Plan	   *plan = queryDesc->plantree;	EState	   *estate = queryDesc->estate;	PlanState  *planstate;	List	   *rangeTable;	Relation	intoRelationDesc;	bool		do_select_into;	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, operation);	/*	 * 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;			numResultRelations = length(resultRelations);			resultRelInfos = (ResultRelInfo *)				palloc(numResultRelations * sizeof(ResultRelInfo));			resultRelInfo = resultRelInfos;

⌨️ 快捷键说明

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