pquery.c

来自「PostgreSQL7.4.6 for Linux」· C语言 代码 · 共 1,183 行 · 第 1/3 页

C
1,183
字号
/*------------------------------------------------------------------------- * * pquery.c *	  POSTGRES process query command code * * 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/tcop/pquery.c,v 1.73.2.1 2004/03/05 00:21:51 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "executor/executor.h"#include "miscadmin.h"#include "tcop/tcopprot.h"#include "tcop/pquery.h"#include "tcop/utility.h"#include "utils/guc.h"#include "utils/memutils.h"static uint32 RunFromStore(Portal portal, ScanDirection direction, long count,			 DestReceiver *dest);static long PortalRunSelect(Portal portal, bool forward, long count,				DestReceiver *dest);static void PortalRunUtility(Portal portal, Query *query,				 DestReceiver *dest, char *completionTag);static void PortalRunMulti(Portal portal,			   DestReceiver *dest, DestReceiver *altdest,			   char *completionTag);static long DoPortalRunFetch(Portal portal,				 FetchDirection fdirection,				 long count,				 DestReceiver *dest);static void DoPortalRewind(Portal portal);/* * CreateQueryDesc */QueryDesc *CreateQueryDesc(Query *parsetree,				Plan *plantree,				DestReceiver *dest,				ParamListInfo params,				bool doInstrument){	QueryDesc  *qd = (QueryDesc *) palloc(sizeof(QueryDesc));	qd->operation = parsetree->commandType;		/* operation */	qd->parsetree = parsetree;	/* parse tree */	qd->plantree = plantree;	/* plan */	qd->dest = dest;			/* output dest */	qd->params = params;		/* parameter values passed into query */	qd->doInstrument = doInstrument;	/* instrumentation wanted? */	/* null these fields until set by ExecutorStart */	qd->tupDesc = NULL;	qd->estate = NULL;	qd->planstate = NULL;	return qd;}/* * FreeQueryDesc */voidFreeQueryDesc(QueryDesc *qdesc){	/* Can't be a live query */	Assert(qdesc->estate == NULL);	/* Only the QueryDesc itself need be freed */	pfree(qdesc);}/* * ProcessQuery *		Execute a single query * *	parsetree: the query tree *	plan: the plan tree for the query *	params: any parameters needed *	dest: where to send results *	completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE *		in which to store a command completion status string. * * completionTag may be NULL if caller doesn't want a status string. * * Must be called in a memory context that will be reset or deleted on * error; otherwise the executor's memory usage will be leaked. */voidProcessQuery(Query *parsetree,			 Plan *plan,			 ParamListInfo params,			 DestReceiver *dest,			 char *completionTag){	int			operation = parsetree->commandType;	QueryDesc  *queryDesc;	/*	 * Check for special-case destinations	 */	if (operation == CMD_SELECT)	{		if (parsetree->into != NULL)		{			/*			 * SELECT INTO table (a/k/a CREATE AS ... SELECT).			 *			 * Override the normal communication destination; execMain.c			 * special-cases this case.  (Perhaps would be cleaner to have			 * an additional destination type?)			 */			dest = None_Receiver;		}	}	/*	 * Create the QueryDesc object	 */	queryDesc = CreateQueryDesc(parsetree, plan, dest, params, false);	/*	 * Call ExecStart to prepare the plan for execution	 */	ExecutorStart(queryDesc, false, false);	/*	 * Run the plan to completion.	 */	ExecutorRun(queryDesc, ForwardScanDirection, 0L);	/*	 * Build command completion status string, if caller wants one.	 */	if (completionTag)	{		Oid			lastOid;		switch (operation)		{			case CMD_SELECT:				strcpy(completionTag, "SELECT");				break;			case CMD_INSERT:				if (queryDesc->estate->es_processed == 1)					lastOid = queryDesc->estate->es_lastoid;				else					lastOid = InvalidOid;				snprintf(completionTag, COMPLETION_TAG_BUFSIZE,				"INSERT %u %u", lastOid, queryDesc->estate->es_processed);				break;			case CMD_UPDATE:				snprintf(completionTag, COMPLETION_TAG_BUFSIZE,						 "UPDATE %u", queryDesc->estate->es_processed);				break;			case CMD_DELETE:				snprintf(completionTag, COMPLETION_TAG_BUFSIZE,						 "DELETE %u", queryDesc->estate->es_processed);				break;			default:				strcpy(completionTag, "???");				break;		}	}	/*	 * Now, we close down all the scans and free allocated resources.	 */	ExecutorEnd(queryDesc);	FreeQueryDesc(queryDesc);}/* * ChoosePortalStrategy *		Select portal execution strategy given the intended query list. * * See the comments in portal.h. */PortalStrategyChoosePortalStrategy(List *parseTrees){	PortalStrategy strategy;	strategy = PORTAL_MULTI_QUERY;		/* default assumption */	if (length(parseTrees) == 1)	{		Query	   *query = (Query *) lfirst(parseTrees);		if (query->commandType == CMD_SELECT &&			query->canSetTag &&			query->into == NULL)			strategy = PORTAL_ONE_SELECT;		else if (query->commandType == CMD_UTILITY &&				 query->canSetTag &&				 query->utilityStmt != NULL)		{			if (UtilityReturnsTuples(query->utilityStmt))				strategy = PORTAL_UTIL_SELECT;		}	}	return strategy;}/* * PortalStart *		Prepare a portal for execution. * * Caller must already have created the portal, done PortalDefineQuery(), * and adjusted portal options if needed.  If parameters are needed by * the query, they must be passed in here (caller is responsible for * giving them appropriate lifetime). * * On return, portal is ready to accept PortalRun() calls, and the result * tupdesc (if any) is known. */voidPortalStart(Portal portal, ParamListInfo params){	MemoryContext oldContext;	QueryDesc  *queryDesc;	AssertArg(PortalIsValid(portal));	AssertState(portal->queryContext != NULL);	/* query defined? */	AssertState(!portal->portalReady);	/* else extra PortalStart */	oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));	/* Must remember portal param list, if any */	portal->portalParams = params;	/*	 * Determine the portal execution strategy	 */	portal->strategy = ChoosePortalStrategy(portal->parseTrees);	/*	 * Fire her up according to the strategy	 */	switch (portal->strategy)	{		case PORTAL_ONE_SELECT:			/*			 * Must set query snapshot before starting executor.			 */			SetQuerySnapshot();			/*			 * Create QueryDesc in portal's context; for the moment, set			 * the destination to None.			 */			queryDesc = CreateQueryDesc((Query *) lfirst(portal->parseTrees),									  (Plan *) lfirst(portal->planTrees),										None_Receiver,										params,										false);			/*			 * Call ExecStart to prepare the plan for execution			 */			ExecutorStart(queryDesc, false, false);			/*			 * This tells PortalCleanup to shut down the executor			 */			portal->queryDesc = queryDesc;			/*			 * Remember tuple descriptor (computed by ExecutorStart)			 */			portal->tupDesc = queryDesc->tupDesc;			/*			 * Reset cursor position data to "start of query"			 */			portal->atStart = true;			portal->atEnd = false;		/* allow fetches */			portal->portalPos = 0;			portal->posOverflow = false;			break;		case PORTAL_UTIL_SELECT:			/*			 * We don't set query snapshot here, because PortalRunUtility			 * will take care of it.			 */			portal->tupDesc =				UtilityTupleDescriptor(((Query *) lfirst(portal->parseTrees))->utilityStmt);			/*			 * Reset cursor position data to "start of query"			 */			portal->atStart = true;			portal->atEnd = false;		/* allow fetches */			portal->portalPos = 0;			portal->posOverflow = false;			break;		case PORTAL_MULTI_QUERY:			/* Need do nothing now */			portal->tupDesc = NULL;			break;	}	MemoryContextSwitchTo(oldContext);	portal->portalReady = true;}/* * PortalSetResultFormat *		Select the format codes for a portal's output. * * This must be run after PortalStart for a portal that will be read by * a Remote or RemoteExecute destination.  It is not presently needed for * other destination types. * * formats[] is the client format request, as per Bind message conventions. */voidPortalSetResultFormat(Portal portal, int nFormats, int16 *formats){	int			natts;	int			i;	/* Do nothing if portal won't return tuples */	if (portal->tupDesc == NULL)		return;	natts = portal->tupDesc->natts;	/* +1 avoids palloc(0) if no columns */	portal->formats = (int16 *)		MemoryContextAlloc(PortalGetHeapMemory(portal),						   (natts + 1) * sizeof(int16));	if (nFormats > 1)	{		/* format specified for each column */		if (nFormats != natts)			ereport(ERROR,					(errcode(ERRCODE_PROTOCOL_VIOLATION),					 errmsg("bind message has %d result formats but query has %d columns",							nFormats, natts)));		memcpy(portal->formats, formats, natts * sizeof(int16));	}	else if (nFormats > 0)	{		/* single format specified, use for all columns */		int16		format1 = formats[0];		for (i = 0; i < natts; i++)			portal->formats[i] = format1;	}	else	{		/* use default format for all columns */		for (i = 0; i < natts; i++)			portal->formats[i] = 0;	}}/* * PortalRun *		Run a portal's query or queries. * * count <= 0 is interpreted as a no-op: the destination gets started up * and shut down, but nothing else happens.  Also, count == FETCH_ALL is * interpreted as "all rows".  Note that count is ignored in multi-query * situations, where we always run the portal to completion. * * dest: where to send output of primary (canSetTag) query * * altdest: where to send output of non-primary queries * * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE *		in which to store a command completion status string. *		May be NULL if caller doesn't want a status string. * * Returns TRUE if the portal's execution is complete, FALSE if it was * suspended due to exhaustion of the count parameter. */boolPortalRun(Portal portal, long count,		  DestReceiver *dest, DestReceiver *altdest,		  char *completionTag)

⌨️ 快捷键说明

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