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

📄 execmain.c

📁 PostgreSQL 8.1.4的源码 适用于Linux下的开源数据库系统
💻 C
📖 第 1 页 / 共 5 页
字号:
/*------------------------------------------------------------------------- * * 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-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION *	  $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.256.2.6 2006/04/26 23:01:58 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "access/heapam.h"#include "access/xlog.h"#include "catalog/heap.h"#include "catalog/namespace.h"#include "commands/tablecmds.h"#include "commands/tablespace.h"#include "commands/trigger.h"#include "executor/execdebug.h"#include "executor/execdefs.h"#include "executor/instrument.h"#include "miscadmin.h"#include "optimizer/clauses.h"#include "optimizer/var.h"#include "parser/parsetree.h"#include "storage/smgr.h"#include "utils/acl.h"#include "utils/guc.h"#include "utils/lsyscache.h"#include "utils/memutils.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,				  bool doInstrument);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);static void ExecCheckXactReadOnly(Query *parsetree);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 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 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 (XactReadOnly && !explainOnly)		ExecCheckXactReadOnly(queryDesc->parsetree);	/*	 * 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));	/*	 * Copy other important information into the EState	 */	estate->es_snapshot = queryDesc->snapshot;	estate->es_crosscheck_snapshot = queryDesc->crosscheck_snapshot;	estate->es_instrument = queryDesc->doInstrument;	/*	 * 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){	ListCell   *l;	foreach(l, rangeTable)	{		RangeTblEntry *rte = lfirst(l);		ExecCheckRTEPerms(rte);	}}/* * ExecCheckRTEPerms *		Check access permissions for a single RTE. */static voidExecCheckRTEPerms(RangeTblEntry *rte){	AclMode		requiredPerms;	Oid			relOid;	Oid			userid;	/*	 * Only plain-relation RTEs need to be checked here.  Subquery RTEs are	 * checked by ExecInitSubqueryScan if the subquery is still a separate	 * subquery --- if it's been pulled up into our query level then the RTEs	 * are in our rangetable and will 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;	/*	 * No work if requiredPerms is empty.	 */	requiredPerms = rte->requiredPerms;	if (requiredPerms == 0)		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();	/*	 * We must have *all* the requiredPerms bits, so use aclmask not aclcheck.	 */	if (pg_class_aclmask(relOid, userid, requiredPerms, ACLMASK_ALL)		!= requiredPerms)		aclcheck_error(ACLCHECK_NO_PRIV, ACL_KIND_CLASS,					   get_rel_name(relOid));}/* * Check that the query does not imply any writes to non-temp tables. */static voidExecCheckXactReadOnly(Query *parsetree){	ListCell   *l;	/*	 * CREATE TABLE AS or SELECT INTO?	 *	 * XXX should we allow this if the destination is temp?	 */	if (parsetree->into != NULL)		goto fail;	/* Fail if write permissions are requested on any non-temp table */	foreach(l, parsetree->rtable)	{		RangeTblEntry *rte = lfirst(l);		if (rte->rtekind == RTE_SUBQUERY)		{			ExecCheckXactReadOnly(rte->subquery);			continue;		}		if (rte->rtekind != RTE_RELATION)			continue;		if ((rte->requiredPerms & (~ACL_SELECT)) == 0)			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;

⌨️ 快捷键说明

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