mirror of
				https://github.com/postgres/postgres.git
				synced 2025-10-31 00:03:57 -04:00 
			
		
		
		
	Clean up BeginCommand and related routines. BeginCommand and EndCommand
are now both invoked once per received SQL command (raw parsetree) from pg_exec_query_string. BeginCommand is actually just an empty routine at the moment --- all its former operations have been pushed into tuple receiver setup routines in printtup.c. This makes for a clean distinction between BeginCommand/EndCommand (once per command) and the tuple receiver setup/teardown routines (once per ExecutorRun call), whereas the old code was quite ad hoc. Along the way, clean up the calling conventions for ExecutorRun a little bit.
This commit is contained in:
		
							parent
							
								
									e22c9c4475
								
							
						
					
					
						commit
						6779c55c22
					
				| @ -1,15 +1,15 @@ | |||||||
| /*-------------------------------------------------------------------------
 | /*-------------------------------------------------------------------------
 | ||||||
|  * |  * | ||||||
|  * printtup.c |  * printtup.c | ||||||
|  *	  Routines to print out tuples to the destination (binary or non-binary |  *	  Routines to print out tuples to the destination (both frontend | ||||||
|  *	  portals, frontend/interactive backend, etc.). |  *	  clients and interactive backends are supported here). | ||||||
|  |  * | ||||||
|  * |  * | ||||||
|  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group |  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group | ||||||
|  * Portions Copyright (c) 1994, Regents of the University of California |  * Portions Copyright (c) 1994, Regents of the University of California | ||||||
|  * |  * | ||||||
|  * |  | ||||||
|  * IDENTIFICATION |  * IDENTIFICATION | ||||||
|  *	  $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.60 2001/10/25 05:49:20 momjian Exp $ |  *	  $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.61 2002/02/27 19:34:09 tgl Exp $ | ||||||
|  * |  * | ||||||
|  *------------------------------------------------------------------------- |  *------------------------------------------------------------------------- | ||||||
|  */ |  */ | ||||||
| @ -18,10 +18,12 @@ | |||||||
| #include "access/heapam.h" | #include "access/heapam.h" | ||||||
| #include "access/printtup.h" | #include "access/printtup.h" | ||||||
| #include "catalog/pg_type.h" | #include "catalog/pg_type.h" | ||||||
|  | #include "libpq/libpq.h" | ||||||
| #include "libpq/pqformat.h" | #include "libpq/pqformat.h" | ||||||
| #include "utils/syscache.h" | #include "utils/syscache.h" | ||||||
| 
 | 
 | ||||||
| static void printtup_setup(DestReceiver *self, TupleDesc typeinfo); | static void printtup_setup(DestReceiver *self, int operation, | ||||||
|  | 						   const char *portalName, TupleDesc typeinfo); | ||||||
| static void printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self); | static void printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self); | ||||||
| static void printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self); | static void printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self); | ||||||
| static void printtup_cleanup(DestReceiver *self); | static void printtup_cleanup(DestReceiver *self); | ||||||
| @ -97,17 +99,56 @@ printtup_create_DR(bool isBinary) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| printtup_setup(DestReceiver *self, TupleDesc typeinfo) | printtup_setup(DestReceiver *self, int operation, | ||||||
|  | 			   const char *portalName, TupleDesc typeinfo) | ||||||
| { | { | ||||||
|  | 	/*
 | ||||||
|  | 	 * Send portal name to frontend. | ||||||
|  | 	 * | ||||||
|  | 	 * If portal name not specified, use "blank" portal. | ||||||
|  | 	 */ | ||||||
|  | 	if (portalName == NULL) | ||||||
|  | 		portalName = "blank"; | ||||||
|  | 
 | ||||||
|  | 	pq_puttextmessage('P', portalName); | ||||||
|  | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * if this is a retrieve, then we send back the tuple | ||||||
|  | 	 * descriptor of the tuples. | ||||||
|  | 	 */ | ||||||
|  | 	if (operation == CMD_SELECT) | ||||||
|  | 	{ | ||||||
|  | 		Form_pg_attribute *attrs = typeinfo->attrs; | ||||||
|  | 		int			natts = typeinfo->natts; | ||||||
|  | 		int			i; | ||||||
|  | 		StringInfoData buf; | ||||||
|  | 
 | ||||||
|  | 		pq_beginmessage(&buf); | ||||||
|  | 		pq_sendbyte(&buf, 'T'); /* tuple descriptor message type */ | ||||||
|  | 		pq_sendint(&buf, natts, 2);	/* # of attrs in tuples */ | ||||||
|  | 
 | ||||||
|  | 		for (i = 0; i < natts; ++i) | ||||||
|  | 		{ | ||||||
|  | 			pq_sendstring(&buf, NameStr(attrs[i]->attname)); | ||||||
|  | 			pq_sendint(&buf, (int) attrs[i]->atttypid, | ||||||
|  | 					   sizeof(attrs[i]->atttypid)); | ||||||
|  | 			pq_sendint(&buf, attrs[i]->attlen, | ||||||
|  | 					   sizeof(attrs[i]->attlen)); | ||||||
|  | 			if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2) | ||||||
|  | 				pq_sendint(&buf, attrs[i]->atttypmod, | ||||||
|  | 						   sizeof(attrs[i]->atttypmod)); | ||||||
|  | 		} | ||||||
|  | 		pq_endmessage(&buf); | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	/* ----------------
 | 	/* ----------------
 | ||||||
| 	 * We could set up the derived attr info at this time, but we postpone it | 	 * We could set up the derived attr info at this time, but we postpone it | ||||||
| 	 * until the first call of printtup, for 3 reasons: | 	 * until the first call of printtup, for 2 reasons: | ||||||
| 	 * 1. We don't waste time (compared to the old way) if there are no | 	 * 1. We don't waste time (compared to the old way) if there are no | ||||||
| 	 *	  tuples at all to output. | 	 *	  tuples at all to output. | ||||||
| 	 * 2. Checking in printtup allows us to handle the case that the tuples | 	 * 2. Checking in printtup allows us to handle the case that the tuples | ||||||
| 	 *	  change type midway through (although this probably can't happen in | 	 *	  change type midway through (although this probably can't happen in | ||||||
| 	 *	  the current executor). | 	 *	  the current executor). | ||||||
| 	 * 3. Right now, ExecutorRun passes a NULL for typeinfo anyway :-( |  | ||||||
| 	 * ---------------- | 	 * ---------------- | ||||||
| 	 */ | 	 */ | ||||||
| } | } | ||||||
| @ -267,12 +308,12 @@ printatt(unsigned attributeId, | |||||||
|  *		showatts |  *		showatts | ||||||
|  * ---------------- |  * ---------------- | ||||||
|  */ |  */ | ||||||
| void | static void | ||||||
| showatts(char *name, TupleDesc tupleDesc) | showatts(const char *name, TupleDesc tupleDesc) | ||||||
| { | { | ||||||
| 	int			i; |  | ||||||
| 	int			natts = tupleDesc->natts; | 	int			natts = tupleDesc->natts; | ||||||
| 	Form_pg_attribute *attinfo = tupleDesc->attrs; | 	Form_pg_attribute *attinfo = tupleDesc->attrs; | ||||||
|  | 	int			i; | ||||||
| 
 | 
 | ||||||
| 	puts(name); | 	puts(name); | ||||||
| 	for (i = 0; i < natts; ++i) | 	for (i = 0; i < natts; ++i) | ||||||
| @ -281,7 +322,24 @@ showatts(char *name, TupleDesc tupleDesc) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* ----------------
 | /* ----------------
 | ||||||
|  *		debugtup |  *		debugSetup - prepare to print tuples for an interactive backend | ||||||
|  |  * ---------------- | ||||||
|  |  */ | ||||||
|  | void | ||||||
|  | debugSetup(DestReceiver *self, int operation, | ||||||
|  | 		   const char *portalName, TupleDesc typeinfo) | ||||||
|  | { | ||||||
|  | 	/*
 | ||||||
|  | 	 * show the return type of the tuples | ||||||
|  | 	 */ | ||||||
|  | 	if (portalName == NULL) | ||||||
|  | 		portalName = "blank"; | ||||||
|  | 
 | ||||||
|  | 	showatts(portalName, typeinfo); | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | /* ----------------
 | ||||||
|  |  *		debugtup - print one tuple for an interactive backend | ||||||
|  * ---------------- |  * ---------------- | ||||||
|  */ |  */ | ||||||
| void | void | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ | |||||||
|  * |  * | ||||||
|  * |  * | ||||||
|  * IDENTIFICATION |  * IDENTIFICATION | ||||||
|  *	  $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.76 2001/10/25 05:49:20 momjian Exp $ |  *	  $Header: /cvsroot/pgsql/src/backend/access/common/tupdesc.c,v 1.77 2002/02/27 19:34:11 tgl Exp $ | ||||||
|  * |  * | ||||||
|  * NOTES |  * NOTES | ||||||
|  *	  some of the executor utility code such as "ExecTypeFromTL" should be |  *	  some of the executor utility code such as "ExecTypeFromTL" should be | ||||||
| @ -432,7 +432,7 @@ TupleDescInitEntry(TupleDesc desc, | |||||||
| 	 * | 	 * | ||||||
| 	 * (Why not just make the atttypid point to the OID type, instead of the | 	 * (Why not just make the atttypid point to the OID type, instead of the | ||||||
| 	 * type the query returns?	Because the executor uses the atttypid to | 	 * type the query returns?	Because the executor uses the atttypid to | ||||||
| 	 * tell the front end what type will be returned (in BeginCommand), | 	 * tell the front end what type will be returned, | ||||||
| 	 * and in the end the type returned will be the result of the query, | 	 * and in the end the type returned will be the result of the query, | ||||||
| 	 * not an OID.) | 	 * not an OID.) | ||||||
| 	 * | 	 * | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ | |||||||
|  * |  * | ||||||
|  * |  * | ||||||
|  * IDENTIFICATION |  * IDENTIFICATION | ||||||
|  *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.155 2002/02/26 22:47:04 tgl Exp $ |  *	  $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.156 2002/02/27 19:34:38 tgl Exp $ | ||||||
|  * |  * | ||||||
|  * NOTES |  * NOTES | ||||||
|  *	  The PerformAddAttribute() code, like most of the relation |  *	  The PerformAddAttribute() code, like most of the relation | ||||||
| @ -113,6 +113,7 @@ PerformPortalFetch(char *name, | |||||||
| 	QueryDesc  *queryDesc; | 	QueryDesc  *queryDesc; | ||||||
| 	EState	   *estate; | 	EState	   *estate; | ||||||
| 	MemoryContext oldcontext; | 	MemoryContext oldcontext; | ||||||
|  | 	ScanDirection direction; | ||||||
| 	CommandId	savedId; | 	CommandId	savedId; | ||||||
| 	bool		temp_desc = false; | 	bool		temp_desc = false; | ||||||
| 
 | 
 | ||||||
| @ -145,6 +146,9 @@ PerformPortalFetch(char *name, | |||||||
| 	 */ | 	 */ | ||||||
| 	oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal)); | 	oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal)); | ||||||
| 
 | 
 | ||||||
|  | 	queryDesc = PortalGetQueryDesc(portal); | ||||||
|  | 	estate = PortalGetState(portal); | ||||||
|  | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * If the requested destination is not the same as the query's | 	 * If the requested destination is not the same as the query's | ||||||
| 	 * original destination, make a temporary QueryDesc with the proper | 	 * original destination, make a temporary QueryDesc with the proper | ||||||
| @ -156,9 +160,6 @@ PerformPortalFetch(char *name, | |||||||
| 	 * original dest.  This is necessary since a FETCH command will pass | 	 * original dest.  This is necessary since a FETCH command will pass | ||||||
| 	 * dest = Remote, not knowing whether the cursor is binary or not. | 	 * dest = Remote, not knowing whether the cursor is binary or not. | ||||||
| 	 */ | 	 */ | ||||||
| 	queryDesc = PortalGetQueryDesc(portal); |  | ||||||
| 	estate = PortalGetState(portal); |  | ||||||
| 
 |  | ||||||
| 	if (dest != queryDesc->dest && | 	if (dest != queryDesc->dest && | ||||||
| 		!(queryDesc->dest == RemoteInternal && dest == Remote)) | 		!(queryDesc->dest == RemoteInternal && dest == Remote)) | ||||||
| 	{ | 	{ | ||||||
| @ -170,19 +171,6 @@ PerformPortalFetch(char *name, | |||||||
| 		temp_desc = true; | 		temp_desc = true; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/*
 |  | ||||||
| 	 * Tell the destination to prepare to receive some tuples. |  | ||||||
| 	 */ |  | ||||||
| 	BeginCommand(name, |  | ||||||
| 				 queryDesc->operation, |  | ||||||
| 				 PortalGetTupleDesc(portal), |  | ||||||
| 				 false,			/* portal fetches don't end up in
 |  | ||||||
| 								 * relations */ |  | ||||||
| 				 false,			/* this is a portal fetch, not a "retrieve
 |  | ||||||
| 								 * portal" */ |  | ||||||
| 				 NULL,			/* not used */ |  | ||||||
| 				 queryDesc->dest); |  | ||||||
| 
 |  | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Restore the scanCommandId that was current when the cursor was | 	 * Restore the scanCommandId that was current when the cursor was | ||||||
| 	 * opened.  This ensures that we see the same tuples throughout the | 	 * opened.  This ensures that we see the same tuples throughout the | ||||||
| @ -194,47 +182,49 @@ PerformPortalFetch(char *name, | |||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Determine which direction to go in, and check to see if we're | 	 * Determine which direction to go in, and check to see if we're | ||||||
| 	 * already at the end of the available tuples in that direction.  If | 	 * already at the end of the available tuples in that direction.  If | ||||||
| 	 * so, do nothing.	(This check exists because not all plan node types | 	 * so, set the direction to NoMovement to avoid trying to fetch any | ||||||
|  | 	 * tuples.  (This check exists because not all plan node types | ||||||
| 	 * are robust about being called again if they've already returned | 	 * are robust about being called again if they've already returned | ||||||
| 	 * NULL once.)	If it's OK to do the fetch, call the executor.  Then, | 	 * NULL once.)  Then call the executor (we must not skip this, because | ||||||
| 	 * update the atStart/atEnd state depending on the number of tuples | 	 * the destination needs to see a setup and shutdown even if no tuples | ||||||
| 	 * that were retrieved. | 	 * are available).  Finally, update the atStart/atEnd state depending | ||||||
|  | 	 * on the number of tuples that were retrieved. | ||||||
| 	 */ | 	 */ | ||||||
| 	if (forward) | 	if (forward) | ||||||
| 	{ | 	{ | ||||||
| 		if (!portal->atEnd) | 		if (portal->atEnd) | ||||||
| 		{ | 			direction = NoMovementScanDirection; | ||||||
| 			ExecutorRun(queryDesc, estate, EXEC_FOR, (long) count); | 		else | ||||||
|  | 			direction = ForwardScanDirection; | ||||||
| 
 | 
 | ||||||
| 			if (estate->es_processed > 0) | 		ExecutorRun(queryDesc, estate, direction, (long) count); | ||||||
| 				portal->atStart = false;		/* OK to back up now */ |  | ||||||
| 			if (count <= 0 || (int) estate->es_processed < count) |  | ||||||
| 				portal->atEnd = true;	/* we retrieved 'em all */ |  | ||||||
| 
 | 
 | ||||||
| 			if (completionTag) | 		if (estate->es_processed > 0) | ||||||
| 				snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u", | 			portal->atStart = false; /* OK to back up now */ | ||||||
| 						 (dest == None) ? "MOVE" : "FETCH", | 		if (count <= 0 || (int) estate->es_processed < count) | ||||||
| 						 estate->es_processed); | 			portal->atEnd = true;	/* we retrieved 'em all */ | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		if (!portal->atStart) | 		if (portal->atStart) | ||||||
| 		{ | 			direction = NoMovementScanDirection; | ||||||
| 			ExecutorRun(queryDesc, estate, EXEC_BACK, (long) count); | 		else | ||||||
|  | 			direction = BackwardScanDirection; | ||||||
| 
 | 
 | ||||||
| 			if (estate->es_processed > 0) | 		ExecutorRun(queryDesc, estate, direction, (long) count); | ||||||
| 				portal->atEnd = false;	/* OK to go forward now */ |  | ||||||
| 			if (count <= 0 || (int) estate->es_processed < count) |  | ||||||
| 				portal->atStart = true; /* we retrieved 'em all */ |  | ||||||
| 
 | 
 | ||||||
| 			if (completionTag) | 		if (estate->es_processed > 0) | ||||||
| 				snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u", | 			portal->atEnd = false;	/* OK to go forward now */ | ||||||
| 						 (dest == None) ? "MOVE" : "FETCH", | 		if (count <= 0 || (int) estate->es_processed < count) | ||||||
| 						 estate->es_processed); | 			portal->atStart = true; /* we retrieved 'em all */ | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	/* Return command status if wanted */ | ||||||
|  | 	if (completionTag) | ||||||
|  | 		snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u", | ||||||
|  | 				 (dest == None) ? "MOVE" : "FETCH", | ||||||
|  | 				 estate->es_processed); | ||||||
|  | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Restore outer command ID. | 	 * Restore outer command ID. | ||||||
| 	 */ | 	 */ | ||||||
|  | |||||||
| @ -19,7 +19,7 @@ | |||||||
|  *	query plan and ExecutorEnd() should always be called at the end of |  *	query plan and ExecutorEnd() should always be called at the end of | ||||||
|  *	execution of a plan. |  *	execution of a plan. | ||||||
|  * |  * | ||||||
|  *	ExecutorRun accepts 'feature' and 'count' arguments that specify whether |  *	ExecutorRun accepts direction and count arguments that specify whether | ||||||
|  *	the plan is to be executed forwards, backwards, and for how many tuples. |  *	the plan is to be executed forwards, backwards, and for how many tuples. | ||||||
|  * |  * | ||||||
|  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group |  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group | ||||||
| @ -27,7 +27,7 @@ | |||||||
|  * |  * | ||||||
|  * |  * | ||||||
|  * IDENTIFICATION |  * IDENTIFICATION | ||||||
|  *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.149 2001/10/25 05:49:27 momjian Exp $ |  *	  $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.150 2002/02/27 19:34:48 tgl Exp $ | ||||||
|  * |  * | ||||||
|  *------------------------------------------------------------------------- |  *------------------------------------------------------------------------- | ||||||
|  */ |  */ | ||||||
| @ -88,7 +88,7 @@ static void ExecCheckRTEPerms(RangeTblEntry *rte, CmdType operation); | |||||||
|  *		query plan |  *		query plan | ||||||
|  * |  * | ||||||
|  *		returns a TupleDesc which describes the attributes of the tuples to |  *		returns a TupleDesc which describes the attributes of the tuples to | ||||||
|  *		be returned by the query. |  *		be returned by the query.  (Same value is saved in queryDesc) | ||||||
|  * |  * | ||||||
|  * NB: the CurrentMemoryContext when this is called must be the context |  * NB: the CurrentMemoryContext when this is called must be the context | ||||||
|  * to be used as the per-query context for the query plan.	ExecutorRun() |  * to be used as the per-query context for the query plan.	ExecutorRun() | ||||||
| @ -137,6 +137,8 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate) | |||||||
| 					  queryDesc->plantree, | 					  queryDesc->plantree, | ||||||
| 					  estate); | 					  estate); | ||||||
| 
 | 
 | ||||||
|  | 	queryDesc->tupDesc = result; | ||||||
|  | 
 | ||||||
| 	return result; | 	return result; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -149,25 +151,23 @@ ExecutorStart(QueryDesc *queryDesc, EState *estate) | |||||||
|  * |  * | ||||||
|  *		ExecutorStart must have been called already. |  *		ExecutorStart must have been called already. | ||||||
|  * |  * | ||||||
|  *		the different features supported are: |  *		If direction is NoMovementScanDirection then nothing is done | ||||||
|  *			 EXEC_RUN:	retrieve all tuples in the forward direction |  *		except to start up/shut down the destination.  Otherwise, | ||||||
|  *			 EXEC_FOR:	retrieve 'count' number of tuples in the forward dir |  *		we retrieve up to 'count' tuples in the specified direction. | ||||||
|  *			 EXEC_BACK: retrieve 'count' number of tuples in the backward dir |  | ||||||
|  *			 EXEC_RETONE: return one tuple but don't 'retrieve' it |  | ||||||
|  *						   used in postquel function processing |  | ||||||
|  * |  * | ||||||
|  *		Note: count = 0 is interpreted as "no limit". |  *		Note: count = 0 is interpreted as "no limit". | ||||||
|  * |  * | ||||||
|  * ---------------------------------------------------------------- |  * ---------------------------------------------------------------- | ||||||
|  */ |  */ | ||||||
| TupleTableSlot * | TupleTableSlot * | ||||||
| ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, long count) | ExecutorRun(QueryDesc *queryDesc, EState *estate, | ||||||
|  | 			ScanDirection direction, long count) | ||||||
| { | { | ||||||
| 	CmdType		operation; | 	CmdType		operation; | ||||||
| 	Plan	   *plan; | 	Plan	   *plan; | ||||||
| 	TupleTableSlot *result; |  | ||||||
| 	CommandDest dest; | 	CommandDest dest; | ||||||
| 	DestReceiver *destfunc; | 	DestReceiver *destfunc; | ||||||
|  | 	TupleTableSlot *result; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * sanity checks | 	 * sanity checks | ||||||
| @ -181,69 +181,33 @@ ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, long count) | |||||||
| 	operation = queryDesc->operation; | 	operation = queryDesc->operation; | ||||||
| 	plan = queryDesc->plantree; | 	plan = queryDesc->plantree; | ||||||
| 	dest = queryDesc->dest; | 	dest = queryDesc->dest; | ||||||
| 	destfunc = DestToFunction(dest); | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * startup tuple receiver | ||||||
|  | 	 */ | ||||||
| 	estate->es_processed = 0; | 	estate->es_processed = 0; | ||||||
| 	estate->es_lastoid = InvalidOid; | 	estate->es_lastoid = InvalidOid; | ||||||
| 
 | 
 | ||||||
|  | 	destfunc = DestToFunction(dest); | ||||||
|  | 	(*destfunc->setup) (destfunc, (int) operation, | ||||||
|  | 						queryDesc->portalName, queryDesc->tupDesc); | ||||||
|  | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * FIXME: the dest setup function ought to be handed the tuple desc | 	 * run plan | ||||||
| 	 * for the tuples to be output, but I'm not quite sure how to get that |  | ||||||
| 	 * info at this point.	For now, passing NULL is OK because no |  | ||||||
| 	 * existing dest setup function actually uses the pointer. |  | ||||||
| 	 */ | 	 */ | ||||||
| 	(*destfunc->setup) (destfunc, (TupleDesc) NULL); | 	if (direction == NoMovementScanDirection) | ||||||
| 
 | 		result = NULL; | ||||||
| 	switch (feature) | 	else | ||||||
| 	{ | 		result = ExecutePlan(estate, | ||||||
| 		case EXEC_RUN: | 							 plan, | ||||||
| 			result = ExecutePlan(estate, | 							 operation, | ||||||
| 								 plan, | 							 count, | ||||||
| 								 operation, | 							 direction, | ||||||
| 								 count, | 							 destfunc); | ||||||
| 								 ForwardScanDirection, |  | ||||||
| 								 destfunc); |  | ||||||
| 			break; |  | ||||||
| 
 |  | ||||||
| 		case EXEC_FOR: |  | ||||||
| 			result = ExecutePlan(estate, |  | ||||||
| 								 plan, |  | ||||||
| 								 operation, |  | ||||||
| 								 count, |  | ||||||
| 								 ForwardScanDirection, |  | ||||||
| 								 destfunc); |  | ||||||
| 			break; |  | ||||||
| 
 |  | ||||||
| 			/*
 |  | ||||||
| 			 * retrieve next n "backward" tuples |  | ||||||
| 			 */ |  | ||||||
| 		case EXEC_BACK: |  | ||||||
| 			result = ExecutePlan(estate, |  | ||||||
| 								 plan, |  | ||||||
| 								 operation, |  | ||||||
| 								 count, |  | ||||||
| 								 BackwardScanDirection, |  | ||||||
| 								 destfunc); |  | ||||||
| 			break; |  | ||||||
| 
 |  | ||||||
| 			/*
 |  | ||||||
| 			 * return one tuple but don't "retrieve" it. (this is used by |  | ||||||
| 			 * the rule manager..) -cim 9/14/89 |  | ||||||
| 			 */ |  | ||||||
| 		case EXEC_RETONE: |  | ||||||
| 			result = ExecutePlan(estate, |  | ||||||
| 								 plan, |  | ||||||
| 								 operation, |  | ||||||
| 								 ONE_TUPLE, |  | ||||||
| 								 ForwardScanDirection, |  | ||||||
| 								 destfunc); |  | ||||||
| 			break; |  | ||||||
| 
 |  | ||||||
| 		default: |  | ||||||
| 			elog(DEBUG, "ExecutorRun: Unknown feature %d", feature); |  | ||||||
| 			result = NULL; |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| 
 | 
 | ||||||
|  | 	/*
 | ||||||
|  | 	 * shutdown receiver | ||||||
|  | 	 */ | ||||||
| 	(*destfunc->cleanup) (destfunc); | 	(*destfunc->cleanup) (destfunc); | ||||||
| 
 | 
 | ||||||
| 	return result; | 	return result; | ||||||
| @ -916,7 +880,7 @@ EndPlan(Plan *plan, EState *estate) | |||||||
|  * |  * | ||||||
|  *		processes the query plan to retrieve 'numberTuples' tuples in the |  *		processes the query plan to retrieve 'numberTuples' tuples in the | ||||||
|  *		direction specified. |  *		direction specified. | ||||||
|  *		Retrieves all tuples if tupleCount is 0 |  *		Retrieves all tuples if numberTuples is 0 | ||||||
|  * |  * | ||||||
|  *		result is either a slot containing the last tuple in the case |  *		result is either a slot containing the last tuple in the case | ||||||
|  *		of a RETRIEVE or NULL otherwise. |  *		of a RETRIEVE or NULL otherwise. | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ | |||||||
|  * |  * | ||||||
|  * |  * | ||||||
|  * IDENTIFICATION |  * IDENTIFICATION | ||||||
|  *	  $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.48 2002/02/26 22:47:05 tgl Exp $ |  *	  $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.49 2002/02/27 19:34:51 tgl Exp $ | ||||||
|  * |  * | ||||||
|  *------------------------------------------------------------------------- |  *------------------------------------------------------------------------- | ||||||
|  */ |  */ | ||||||
| @ -111,9 +111,8 @@ init_execution_state(char *src, Oid *argOidVect, int nargs) | |||||||
| 
 | 
 | ||||||
| 		nextes->next = NULL; | 		nextes->next = NULL; | ||||||
| 		nextes->status = F_EXEC_START; | 		nextes->status = F_EXEC_START; | ||||||
| 		nextes->qd = CreateQueryDesc(queryTree, | 
 | ||||||
| 									 planTree, | 		nextes->qd = CreateQueryDesc(queryTree, planTree, None, NULL); | ||||||
| 									 None); |  | ||||||
| 		estate = CreateExecutorState(); | 		estate = CreateExecutorState(); | ||||||
| 
 | 
 | ||||||
| 		if (nargs > 0) | 		if (nargs > 0) | ||||||
| @ -268,7 +267,7 @@ postquel_start(execution_state *es) | |||||||
| static TupleTableSlot * | static TupleTableSlot * | ||||||
| postquel_getnext(execution_state *es) | postquel_getnext(execution_state *es) | ||||||
| { | { | ||||||
| 	int			feature; | 	long	count; | ||||||
| 
 | 
 | ||||||
| 	if (es->qd->operation == CMD_UTILITY) | 	if (es->qd->operation == CMD_UTILITY) | ||||||
| 	{ | 	{ | ||||||
| @ -281,9 +280,10 @@ postquel_getnext(execution_state *es) | |||||||
| 		return (TupleTableSlot *) NULL; | 		return (TupleTableSlot *) NULL; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	feature = (LAST_POSTQUEL_COMMAND(es)) ? EXEC_RETONE : EXEC_RUN; | 	/* If it's not the last command, just run it to completion */ | ||||||
|  | 	count = (LAST_POSTQUEL_COMMAND(es)) ? 1L : 0L; | ||||||
| 
 | 
 | ||||||
| 	return ExecutorRun(es->qd, es->estate, feature, 0L); | 	return ExecutorRun(es->qd, es->estate, ForwardScanDirection, count); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ | |||||||
|  * |  * | ||||||
|  * |  * | ||||||
|  * IDENTIFICATION |  * IDENTIFICATION | ||||||
|  *	  $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.66 2002/02/26 22:47:05 tgl Exp $ |  *	  $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.67 2002/02/27 19:34:59 tgl Exp $ | ||||||
|  * |  * | ||||||
|  *------------------------------------------------------------------------- |  *------------------------------------------------------------------------- | ||||||
|  */ |  */ | ||||||
| @ -779,7 +779,7 @@ SPI_cursor_open(char *name, void *plan, Datum *Values, char *Nulls) | |||||||
| 	queryTree->isBinary = false; | 	queryTree->isBinary = false; | ||||||
| 
 | 
 | ||||||
| 	/* Create the QueryDesc object and the executor state */ | 	/* Create the QueryDesc object and the executor state */ | ||||||
| 	queryDesc = CreateQueryDesc(queryTree, planTree, SPI); | 	queryDesc = CreateQueryDesc(queryTree, planTree, SPI, NULL); | ||||||
| 	eState = CreateExecutorState(); | 	eState = CreateExecutorState(); | ||||||
| 
 | 
 | ||||||
| 	/* If the plan has parameters, put them into the executor state */ | 	/* If the plan has parameters, put them into the executor state */ | ||||||
| @ -1023,7 +1023,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan) | |||||||
| 		else if (plan == NULL) | 		else if (plan == NULL) | ||||||
| 		{ | 		{ | ||||||
| 			qdesc = CreateQueryDesc(queryTree, planTree, | 			qdesc = CreateQueryDesc(queryTree, planTree, | ||||||
| 									islastquery ? SPI : None); | 									islastquery ? SPI : None, NULL); | ||||||
| 			state = CreateExecutorState(); | 			state = CreateExecutorState(); | ||||||
| 			res = _SPI_pquery(qdesc, state, islastquery ? tcount : 0); | 			res = _SPI_pquery(qdesc, state, islastquery ? tcount : 0); | ||||||
| 			if (res < 0 || islastquery) | 			if (res < 0 || islastquery) | ||||||
| @ -1033,7 +1033,7 @@ _SPI_execute(char *src, int tcount, _SPI_plan *plan) | |||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| 			qdesc = CreateQueryDesc(queryTree, planTree, | 			qdesc = CreateQueryDesc(queryTree, planTree, | ||||||
| 									islastquery ? SPI : None); | 									islastquery ? SPI : None, NULL); | ||||||
| 			res = _SPI_pquery(qdesc, NULL, islastquery ? tcount : 0); | 			res = _SPI_pquery(qdesc, NULL, islastquery ? tcount : 0); | ||||||
| 			if (res < 0) | 			if (res < 0) | ||||||
| 				return res; | 				return res; | ||||||
| @ -1094,7 +1094,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, char *Nulls, int tcount) | |||||||
| 		else | 		else | ||||||
| 		{ | 		{ | ||||||
| 			qdesc = CreateQueryDesc(queryTree, planTree, | 			qdesc = CreateQueryDesc(queryTree, planTree, | ||||||
| 									islastquery ? SPI : None); | 									islastquery ? SPI : None, NULL); | ||||||
| 			state = CreateExecutorState(); | 			state = CreateExecutorState(); | ||||||
| 			if (nargs > 0) | 			if (nargs > 0) | ||||||
| 			{ | 			{ | ||||||
| @ -1132,7 +1132,6 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount) | |||||||
| 	Query	   *parseTree = queryDesc->parsetree; | 	Query	   *parseTree = queryDesc->parsetree; | ||||||
| 	int			operation = queryDesc->operation; | 	int			operation = queryDesc->operation; | ||||||
| 	CommandDest dest = queryDesc->dest; | 	CommandDest dest = queryDesc->dest; | ||||||
| 	TupleDesc	tupdesc; |  | ||||||
| 	bool		isRetrieveIntoPortal = false; | 	bool		isRetrieveIntoPortal = false; | ||||||
| 	bool		isRetrieveIntoRelation = false; | 	bool		isRetrieveIntoRelation = false; | ||||||
| 	char	   *intoName = NULL; | 	char	   *intoName = NULL; | ||||||
| @ -1174,11 +1173,13 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount) | |||||||
| 
 | 
 | ||||||
| 	if (state == NULL)			/* plan preparation */ | 	if (state == NULL)			/* plan preparation */ | ||||||
| 		return res; | 		return res; | ||||||
|  | 
 | ||||||
| #ifdef SPI_EXECUTOR_STATS | #ifdef SPI_EXECUTOR_STATS | ||||||
| 	if (ShowExecutorStats) | 	if (ShowExecutorStats) | ||||||
| 		ResetUsage(); | 		ResetUsage(); | ||||||
| #endif | #endif | ||||||
| 	tupdesc = ExecutorStart(queryDesc, state); | 
 | ||||||
|  | 	ExecutorStart(queryDesc, state); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Don't work currently --- need to rearrange callers so that we | 	 * Don't work currently --- need to rearrange callers so that we | ||||||
| @ -1188,7 +1189,7 @@ _SPI_pquery(QueryDesc *queryDesc, EState *state, int tcount) | |||||||
| 	if (isRetrieveIntoPortal) | 	if (isRetrieveIntoPortal) | ||||||
| 		elog(FATAL, "SPI_select: retrieve into portal not implemented"); | 		elog(FATAL, "SPI_select: retrieve into portal not implemented"); | ||||||
| 
 | 
 | ||||||
| 	ExecutorRun(queryDesc, state, EXEC_FOR, (long) tcount); | 	ExecutorRun(queryDesc, state, ForwardScanDirection, (long) tcount); | ||||||
| 
 | 
 | ||||||
| 	_SPI_current->processed = state->es_processed; | 	_SPI_current->processed = state->es_processed; | ||||||
| 	save_lastoid = state->es_lastoid; | 	save_lastoid = state->es_lastoid; | ||||||
| @ -1230,6 +1231,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count, | |||||||
| 	QueryDesc  *querydesc; | 	QueryDesc  *querydesc; | ||||||
| 	EState	   *estate; | 	EState	   *estate; | ||||||
| 	MemoryContext oldcontext; | 	MemoryContext oldcontext; | ||||||
|  | 	ScanDirection direction; | ||||||
| 	CommandId	savedId; | 	CommandId	savedId; | ||||||
| 	CommandDest olddest; | 	CommandDest olddest; | ||||||
| 
 | 
 | ||||||
| @ -1268,29 +1270,35 @@ _SPI_cursor_operation(Portal portal, bool forward, int count, | |||||||
| 	/* Run the executor like PerformPortalFetch and remember states */ | 	/* Run the executor like PerformPortalFetch and remember states */ | ||||||
| 	if (forward) | 	if (forward) | ||||||
| 	{ | 	{ | ||||||
| 		if (!portal->atEnd) | 		if (portal->atEnd) | ||||||
| 		{ | 			direction = NoMovementScanDirection; | ||||||
| 			ExecutorRun(querydesc, estate, EXEC_FOR, (long) count); | 		else | ||||||
| 			_SPI_current->processed = estate->es_processed; | 			direction = ForwardScanDirection; | ||||||
| 			if (estate->es_processed > 0) | 
 | ||||||
| 				portal->atStart = false; | 		ExecutorRun(querydesc, estate, direction, (long) count); | ||||||
| 			if (count <= 0 || (int) estate->es_processed < count) | 
 | ||||||
| 				portal->atEnd = true; | 		if (estate->es_processed > 0) | ||||||
| 		} | 			portal->atStart = false; /* OK to back up now */ | ||||||
|  | 		if (count <= 0 || (int) estate->es_processed < count) | ||||||
|  | 			portal->atEnd = true;	/* we retrieved 'em all */ | ||||||
| 	} | 	} | ||||||
| 	else | 	else | ||||||
| 	{ | 	{ | ||||||
| 		if (!portal->atStart) | 		if (portal->atStart) | ||||||
| 		{ | 			direction = NoMovementScanDirection; | ||||||
| 			ExecutorRun(querydesc, estate, EXEC_BACK, (long) count); | 		else | ||||||
| 			_SPI_current->processed = estate->es_processed; | 			direction = BackwardScanDirection; | ||||||
| 			if (estate->es_processed > 0) | 
 | ||||||
| 				portal->atEnd = false; | 		ExecutorRun(querydesc, estate, direction, (long) count); | ||||||
| 			if (count <= 0 || estate->es_processed < count) | 
 | ||||||
| 				portal->atStart = true; | 		if (estate->es_processed > 0) | ||||||
| 		} | 			portal->atEnd = false;	/* OK to go forward now */ | ||||||
|  | 		if (count <= 0 || (int) estate->es_processed < count) | ||||||
|  | 			portal->atStart = true; /* we retrieved 'em all */ | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
|  | 	_SPI_current->processed = estate->es_processed; | ||||||
|  | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Restore outer command ID. | 	 * Restore outer command ID. | ||||||
| 	 */ | 	 */ | ||||||
|  | |||||||
| @ -1,22 +1,22 @@ | |||||||
| /*-------------------------------------------------------------------------
 | /*-------------------------------------------------------------------------
 | ||||||
|  * |  * | ||||||
|  * dest.c |  * dest.c | ||||||
|  *	  support for various communication destinations - see include/tcop/dest.h |  *	  support for communication destinations | ||||||
|  |  * | ||||||
|  * |  * | ||||||
|  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group |  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group | ||||||
|  * Portions Copyright (c) 1994, Regents of the University of California |  * Portions Copyright (c) 1994, Regents of the University of California | ||||||
|  * |  * | ||||||
|  * |  | ||||||
|  * IDENTIFICATION |  * IDENTIFICATION | ||||||
|  *	  $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.47 2002/02/26 22:47:08 tgl Exp $ |  *	  $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.48 2002/02/27 19:35:09 tgl Exp $ | ||||||
|  * |  * | ||||||
|  *------------------------------------------------------------------------- |  *------------------------------------------------------------------------- | ||||||
|  */ |  */ | ||||||
| /*
 | /*
 | ||||||
|  *	 INTERFACE ROUTINES |  *	 INTERFACE ROUTINES | ||||||
|  *		BeginCommand - prepare destination for tuples of the given type |  *		BeginCommand - initialize the destination at start of command | ||||||
|  *		DestToFunction - identify per-tuple processing routines |  *		DestToFunction - identify per-tuple processing routines | ||||||
|  *		EndCommand - tell destination that no more tuples will arrive |  *		EndCommand - clean up the destination at end of command | ||||||
|  *		NullCommand - tell dest that an empty query string was recognized |  *		NullCommand - tell dest that an empty query string was recognized | ||||||
|  *		ReadyForQuery - tell dest that we are ready for a new query |  *		ReadyForQuery - tell dest that we are ready for a new query | ||||||
|  * |  * | ||||||
| @ -24,14 +24,6 @@ | |||||||
|  *		These routines do the appropriate work before and after |  *		These routines do the appropriate work before and after | ||||||
|  *		tuples are returned by a query to keep the backend and the |  *		tuples are returned by a query to keep the backend and the | ||||||
|  *		"destination" portals synchronized. |  *		"destination" portals synchronized. | ||||||
|  * |  | ||||||
|  *		There is a second level of initialization/cleanup performed by the |  | ||||||
|  *		setup/cleanup routines identified by DestToFunction.  This could |  | ||||||
|  *		probably be merged with the work done by BeginCommand/EndCommand, |  | ||||||
|  *		but as of right now BeginCommand/EndCommand are used in a rather |  | ||||||
|  *		unstructured way --- some places call Begin without End, some vice |  | ||||||
|  *		versa --- so I think I'll just leave 'em alone for now.  tgl 1/99. |  | ||||||
|  * |  | ||||||
|  */ |  */ | ||||||
| 
 | 
 | ||||||
| #include "postgres.h" | #include "postgres.h" | ||||||
| @ -51,7 +43,8 @@ donothingReceive(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self) | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| static void | static void | ||||||
| donothingSetup(DestReceiver *self, TupleDesc typeinfo) | donothingSetup(DestReceiver *self, int operation, | ||||||
|  | 			   const char *portalName, TupleDesc typeinfo) | ||||||
| { | { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -68,97 +61,20 @@ static DestReceiver donothingDR = { | |||||||
| 	donothingReceive, donothingSetup, donothingCleanup | 	donothingReceive, donothingSetup, donothingCleanup | ||||||
| }; | }; | ||||||
| static DestReceiver debugtupDR = { | static DestReceiver debugtupDR = { | ||||||
| 	debugtup, donothingSetup, donothingCleanup | 	debugtup, debugSetup, donothingCleanup | ||||||
| }; | }; | ||||||
| static DestReceiver spi_printtupDR = { | static DestReceiver spi_printtupDR = { | ||||||
| 	spi_printtup, donothingSetup, donothingCleanup | 	spi_printtup, donothingSetup, donothingCleanup | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* ----------------
 | /* ----------------
 | ||||||
|  *		BeginCommand - prepare destination for tuples of the given type |  *		BeginCommand - initialize the destination at start of command | ||||||
|  * ---------------- |  * ---------------- | ||||||
|  */ |  */ | ||||||
| void | void | ||||||
| BeginCommand(char *pname, | BeginCommand(const char *commandTag, CommandDest dest) | ||||||
| 			 int operation, |  | ||||||
| 			 TupleDesc tupdesc, |  | ||||||
| 			 bool isIntoRel, |  | ||||||
| 			 bool isIntoPortal, |  | ||||||
| 			 char *tag, |  | ||||||
| 			 CommandDest dest) |  | ||||||
| { | { | ||||||
| 	Form_pg_attribute *attrs = tupdesc->attrs; | 	/* Nothing to do at present */ | ||||||
| 	int			natts = tupdesc->natts; |  | ||||||
| 	int			i; |  | ||||||
| 
 |  | ||||||
| 	switch (dest) |  | ||||||
| 	{ |  | ||||||
| 		case Remote: |  | ||||||
| 		case RemoteInternal: |  | ||||||
| 
 |  | ||||||
| 			/*
 |  | ||||||
| 			 * if this is a "retrieve into portal" query, done because |  | ||||||
| 			 * nothing needs to be sent to the fe. |  | ||||||
| 			 */ |  | ||||||
| 			if (isIntoPortal) |  | ||||||
| 				break; |  | ||||||
| 
 |  | ||||||
| 			/*
 |  | ||||||
| 			 * if portal name not specified for remote query, use the |  | ||||||
| 			 * "blank" portal. |  | ||||||
| 			 */ |  | ||||||
| 			if (pname == NULL) |  | ||||||
| 				pname = "blank"; |  | ||||||
| 
 |  | ||||||
| 			/*
 |  | ||||||
| 			 * send fe info on tuples we're about to send |  | ||||||
| 			 */ |  | ||||||
| 			pq_puttextmessage('P', pname); |  | ||||||
| 
 |  | ||||||
| 			/*
 |  | ||||||
| 			 * if this is a retrieve, then we send back the tuple |  | ||||||
| 			 * descriptor of the tuples.  "retrieve into" is an exception |  | ||||||
| 			 * because no tuples are returned in that case. |  | ||||||
| 			 */ |  | ||||||
| 			if (operation == CMD_SELECT && !isIntoRel) |  | ||||||
| 			{ |  | ||||||
| 				StringInfoData buf; |  | ||||||
| 
 |  | ||||||
| 				pq_beginmessage(&buf); |  | ||||||
| 				pq_sendbyte(&buf, 'T'); /* tuple descriptor message type */ |  | ||||||
| 				pq_sendint(&buf, natts, 2);		/* # of attributes in
 |  | ||||||
| 												 * tuples */ |  | ||||||
| 
 |  | ||||||
| 				for (i = 0; i < natts; ++i) |  | ||||||
| 				{ |  | ||||||
| 					pq_sendstring(&buf, NameStr(attrs[i]->attname)); |  | ||||||
| 					pq_sendint(&buf, (int) attrs[i]->atttypid, |  | ||||||
| 							   sizeof(attrs[i]->atttypid)); |  | ||||||
| 					pq_sendint(&buf, attrs[i]->attlen, |  | ||||||
| 							   sizeof(attrs[i]->attlen)); |  | ||||||
| 					if (PG_PROTOCOL_MAJOR(FrontendProtocol) >= 2) |  | ||||||
| 						pq_sendint(&buf, attrs[i]->atttypmod, |  | ||||||
| 								   sizeof(attrs[i]->atttypmod)); |  | ||||||
| 				} |  | ||||||
| 				pq_endmessage(&buf); |  | ||||||
| 			} |  | ||||||
| 			break; |  | ||||||
| 
 |  | ||||||
| 		case Debug: |  | ||||||
| 
 |  | ||||||
| 			/*
 |  | ||||||
| 			 * show the return type of the tuples |  | ||||||
| 			 */ |  | ||||||
| 			if (pname == NULL) |  | ||||||
| 				pname = "blank"; |  | ||||||
| 
 |  | ||||||
| 			showatts(pname, tupdesc); |  | ||||||
| 			break; |  | ||||||
| 
 |  | ||||||
| 		case None: |  | ||||||
| 		default: |  | ||||||
| 			break; |  | ||||||
| 	} |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* ----------------
 | /* ----------------
 | ||||||
| @ -183,19 +99,15 @@ DestToFunction(CommandDest dest) | |||||||
| 			return &spi_printtupDR; | 			return &spi_printtupDR; | ||||||
| 
 | 
 | ||||||
| 		case None: | 		case None: | ||||||
| 		default: |  | ||||||
| 			return &donothingDR; | 			return &donothingDR; | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/* should never get here */ | ||||||
| 	 * never gets here, but DECstation lint appears to be stupid... |  | ||||||
| 	 */ |  | ||||||
| 
 |  | ||||||
| 	return &donothingDR; | 	return &donothingDR; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| /* ----------------
 | /* ----------------
 | ||||||
|  *		EndCommand - tell destination that query is complete |  *		EndCommand - clean up the destination at end of command | ||||||
|  * ---------------- |  * ---------------- | ||||||
|  */ |  */ | ||||||
| void | void | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ | |||||||
|  * |  * | ||||||
|  * |  * | ||||||
|  * IDENTIFICATION |  * IDENTIFICATION | ||||||
|  *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.248 2002/02/26 22:47:08 tgl Exp $ |  *	  $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.249 2002/02/27 19:35:12 tgl Exp $ | ||||||
|  * |  * | ||||||
|  * NOTES |  * NOTES | ||||||
|  *	  this is the "main" module of the postgres backend and |  *	  this is the "main" module of the postgres backend and | ||||||
| @ -645,6 +645,18 @@ pg_exec_query_string(char *query_string,		/* string to execute */ | |||||||
| 		/* Transaction control statements need some special handling */ | 		/* Transaction control statements need some special handling */ | ||||||
| 		isTransactionStmt = IsA(parsetree, TransactionStmt); | 		isTransactionStmt = IsA(parsetree, TransactionStmt); | ||||||
| 
 | 
 | ||||||
|  | 		/*
 | ||||||
|  | 		 * First we set the command-completion tag to the main query | ||||||
|  | 		 * (as opposed to each of the others that may be generated by | ||||||
|  | 		 * analyze and rewrite).  Also set ps_status and do any special | ||||||
|  | 		 * start-of-SQL-command processing needed by the destination. | ||||||
|  | 		 */ | ||||||
|  | 		commandTag = CreateCommandTag(parsetree); | ||||||
|  | 
 | ||||||
|  | 		set_ps_display(commandTag); | ||||||
|  | 
 | ||||||
|  | 		BeginCommand(commandTag, dest); | ||||||
|  | 
 | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * If we are in an aborted transaction, ignore all commands except | 		 * If we are in an aborted transaction, ignore all commands except | ||||||
| 		 * COMMIT/ABORT.  It is important that this test occur before we | 		 * COMMIT/ABORT.  It is important that this test occur before we | ||||||
| @ -707,18 +719,7 @@ pg_exec_query_string(char *query_string,		/* string to execute */ | |||||||
| 
 | 
 | ||||||
| 		/*
 | 		/*
 | ||||||
| 		 * OK to analyze and rewrite this query. | 		 * OK to analyze and rewrite this query. | ||||||
| 		 */ | 		 * | ||||||
| 		  |  | ||||||
| 		/*
 |  | ||||||
| 		 * First we set the command-completion tag to the main query |  | ||||||
| 		 * (as opposed to each of the others that may be generated by |  | ||||||
| 		 * analyze and rewrite).  Also set ps_status to the main query tag. |  | ||||||
| 		 */ |  | ||||||
| 		commandTag = CreateCommandTag(parsetree); |  | ||||||
| 
 |  | ||||||
| 		set_ps_display(commandTag); |  | ||||||
| 
 |  | ||||||
| 		/*
 |  | ||||||
| 		 * Switch to appropriate context for constructing querytrees (again, | 		 * Switch to appropriate context for constructing querytrees (again, | ||||||
| 		 * these must outlive the execution context). | 		 * these must outlive the execution context). | ||||||
| 		 */ | 		 */ | ||||||
| @ -1688,7 +1689,7 @@ PostgresMain(int argc, char *argv[], const char *username) | |||||||
| 	if (!IsUnderPostmaster) | 	if (!IsUnderPostmaster) | ||||||
| 	{ | 	{ | ||||||
| 		puts("\nPOSTGRES backend interactive interface "); | 		puts("\nPOSTGRES backend interactive interface "); | ||||||
| 		puts("$Revision: 1.248 $ $Date: 2002/02/26 22:47:08 $\n"); | 		puts("$Revision: 1.249 $ $Date: 2002/02/27 19:35:12 $\n"); | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ | |||||||
|  * |  * | ||||||
|  * |  * | ||||||
|  * IDENTIFICATION |  * IDENTIFICATION | ||||||
|  *	  $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.47 2002/02/26 22:47:09 tgl Exp $ |  *	  $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.48 2002/02/27 19:35:16 tgl Exp $ | ||||||
|  * |  * | ||||||
|  *------------------------------------------------------------------------- |  *------------------------------------------------------------------------- | ||||||
|  */ |  */ | ||||||
| @ -30,7 +30,8 @@ | |||||||
| QueryDesc * | QueryDesc * | ||||||
| CreateQueryDesc(Query *parsetree, | CreateQueryDesc(Query *parsetree, | ||||||
| 				Plan *plantree, | 				Plan *plantree, | ||||||
| 				CommandDest dest) | 				CommandDest dest, | ||||||
|  | 				const char *portalName) | ||||||
| { | { | ||||||
| 	QueryDesc  *qd = (QueryDesc *) palloc(sizeof(QueryDesc)); | 	QueryDesc  *qd = (QueryDesc *) palloc(sizeof(QueryDesc)); | ||||||
| 
 | 
 | ||||||
| @ -38,6 +39,9 @@ CreateQueryDesc(Query *parsetree, | |||||||
| 	qd->parsetree = parsetree;	/* parse tree */ | 	qd->parsetree = parsetree;	/* parse tree */ | ||||||
| 	qd->plantree = plantree;	/* plan */ | 	qd->plantree = plantree;	/* plan */ | ||||||
| 	qd->dest = dest;			/* output dest */ | 	qd->dest = dest;			/* output dest */ | ||||||
|  | 	qd->portalName = portalName; /* name, if dest is a portal */ | ||||||
|  | 	qd->tupDesc = NULL;			/* until set by ExecutorStart */ | ||||||
|  | 
 | ||||||
| 	return qd; | 	return qd; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -138,8 +142,7 @@ ProcessQuery(Query *parsetree, | |||||||
| 			 char *completionTag) | 			 char *completionTag) | ||||||
| { | { | ||||||
| 	int			operation = parsetree->commandType; | 	int			operation = parsetree->commandType; | ||||||
| 	bool		isRetrieveIntoPortal; | 	bool		isRetrieveIntoPortal = false; | ||||||
| 	bool		isRetrieveIntoRelation; |  | ||||||
| 	char	   *intoName = NULL; | 	char	   *intoName = NULL; | ||||||
| 	Portal		portal = NULL; | 	Portal		portal = NULL; | ||||||
| 	MemoryContext oldContext = NULL; | 	MemoryContext oldContext = NULL; | ||||||
| @ -148,31 +151,28 @@ ProcessQuery(Query *parsetree, | |||||||
| 	TupleDesc	attinfo; | 	TupleDesc	attinfo; | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * initialize portal/into relation status | 	 * Check for special-case destinations | ||||||
| 	 */ | 	 */ | ||||||
| 	isRetrieveIntoPortal = false; |  | ||||||
| 	isRetrieveIntoRelation = false; |  | ||||||
| 
 |  | ||||||
| 	if (operation == CMD_SELECT) | 	if (operation == CMD_SELECT) | ||||||
| 	{ | 	{ | ||||||
| 		if (parsetree->isPortal) | 		if (parsetree->isPortal) | ||||||
| 		{ | 		{ | ||||||
| 			isRetrieveIntoPortal = true; | 			isRetrieveIntoPortal = true; | ||||||
| 			intoName = parsetree->into; | 			intoName = parsetree->into; | ||||||
| 			if (parsetree->isBinary) | 			/* If binary portal, switch to alternate output format */ | ||||||
| 			{ | 			if (dest == Remote && parsetree->isBinary) | ||||||
| 				/*
 |  | ||||||
| 				 * For internal format portals, we change Remote |  | ||||||
| 				 * (externalized form) to RemoteInternal (internalized |  | ||||||
| 				 * form) |  | ||||||
| 				 */ |  | ||||||
| 				dest = RemoteInternal; | 				dest = RemoteInternal; | ||||||
| 			} |  | ||||||
| 		} | 		} | ||||||
| 		else if (parsetree->into != NULL) | 		else if (parsetree->into != NULL) | ||||||
| 		{ | 		{ | ||||||
| 			/* select into table */ | 			/*
 | ||||||
| 			isRetrieveIntoRelation = true; | 			 * 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; | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| @ -197,16 +197,7 @@ ProcessQuery(Query *parsetree, | |||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Now we can create the QueryDesc object. | 	 * Now we can create the QueryDesc object. | ||||||
| 	 */ | 	 */ | ||||||
| 	queryDesc = CreateQueryDesc(parsetree, plan, dest); | 	queryDesc = CreateQueryDesc(parsetree, plan, dest, intoName); | ||||||
| 
 |  | ||||||
| 	/*
 |  | ||||||
| 	 * When performing a retrieve into, we override the normal |  | ||||||
| 	 * communication destination during the processing of the the query. |  | ||||||
| 	 * This only affects the tuple-output function - the correct |  | ||||||
| 	 * destination will still see the BeginCommand() call. |  | ||||||
| 	 */ |  | ||||||
| 	if (isRetrieveIntoRelation) |  | ||||||
| 		queryDesc->dest = None; |  | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * create a default executor state. | 	 * create a default executor state. | ||||||
| @ -218,18 +209,6 @@ ProcessQuery(Query *parsetree, | |||||||
| 	 */ | 	 */ | ||||||
| 	attinfo = ExecutorStart(queryDesc, state); | 	attinfo = ExecutorStart(queryDesc, state); | ||||||
| 
 | 
 | ||||||
| 	/*
 |  | ||||||
| 	 * report the query's result type information back to the front end or |  | ||||||
| 	 * to whatever destination we're dealing with. |  | ||||||
| 	 */ |  | ||||||
| 	BeginCommand(NULL, |  | ||||||
| 				 operation, |  | ||||||
| 				 attinfo, |  | ||||||
| 				 isRetrieveIntoRelation, |  | ||||||
| 				 isRetrieveIntoPortal, |  | ||||||
| 				 NULL,			/* not used */ |  | ||||||
| 				 dest); |  | ||||||
| 
 |  | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * If retrieve into portal, stop now; we do not run the plan until a | 	 * If retrieve into portal, stop now; we do not run the plan until a | ||||||
| 	 * FETCH command is received. | 	 * FETCH command is received. | ||||||
| @ -256,7 +235,7 @@ ProcessQuery(Query *parsetree, | |||||||
| 	 * Now we get to the important call to ExecutorRun() where we actually | 	 * Now we get to the important call to ExecutorRun() where we actually | ||||||
| 	 * run the plan.. | 	 * run the plan.. | ||||||
| 	 */ | 	 */ | ||||||
| 	ExecutorRun(queryDesc, state, EXEC_RUN, 0L); | 	ExecutorRun(queryDesc, state, ForwardScanDirection, 0L); | ||||||
| 
 | 
 | ||||||
| 	/*
 | 	/*
 | ||||||
| 	 * Build command completion status string, if caller wants one. | 	 * Build command completion status string, if caller wants one. | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ | |||||||
|  * |  * | ||||||
|  * |  * | ||||||
|  * IDENTIFICATION |  * IDENTIFICATION | ||||||
|  *	  $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.45 2002/02/14 15:24:09 tgl Exp $ |  *	  $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.46 2002/02/27 19:35:35 tgl Exp $ | ||||||
|  * |  * | ||||||
|  *------------------------------------------------------------------------- |  *------------------------------------------------------------------------- | ||||||
|  */ |  */ | ||||||
| @ -22,8 +22,8 @@ | |||||||
|  *		sees a |  *		sees a | ||||||
|  *				fetch 1 from FOO |  *				fetch 1 from FOO | ||||||
|  *		the system looks up the portal named "FOO" in the portal table, |  *		the system looks up the portal named "FOO" in the portal table, | ||||||
|  *		gets the planned query and then calls the executor with a feature of |  *		gets the planned query and then calls the executor with a count | ||||||
|  *		'(EXEC_FOR 1).  The executor then runs the query and returns a single |  *		of 1.  The executor then runs the query and returns a single | ||||||
|  *		tuple.	The problem is that we have to hold onto the state of the |  *		tuple.	The problem is that we have to hold onto the state of the | ||||||
|  *		portal query until we see a "close".  This means we have to be |  *		portal query until we see a "close".  This means we have to be | ||||||
|  *		careful about memory management. |  *		careful about memory management. | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ | |||||||
|  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group |  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group | ||||||
|  * Portions Copyright (c) 1994, Regents of the University of California |  * Portions Copyright (c) 1994, Regents of the University of California | ||||||
|  * |  * | ||||||
|  * $Id: printtup.h,v 1.18 2001/11/05 17:46:31 momjian Exp $ |  * $Id: printtup.h,v 1.19 2002/02/27 19:35:40 tgl Exp $ | ||||||
|  * |  * | ||||||
|  *------------------------------------------------------------------------- |  *------------------------------------------------------------------------- | ||||||
|  */ |  */ | ||||||
| @ -18,9 +18,10 @@ | |||||||
| 
 | 
 | ||||||
| extern DestReceiver *printtup_create_DR(bool isBinary); | extern DestReceiver *printtup_create_DR(bool isBinary); | ||||||
| 
 | 
 | ||||||
| extern void showatts(char *name, TupleDesc attinfo); | extern void debugSetup(DestReceiver *self, int operation, | ||||||
|  | 					   const char *portalName, TupleDesc typeinfo); | ||||||
| extern void debugtup(HeapTuple tuple, TupleDesc typeinfo, | extern void debugtup(HeapTuple tuple, TupleDesc typeinfo, | ||||||
| 		 DestReceiver *self); | 					 DestReceiver *self); | ||||||
| 
 | 
 | ||||||
| /* XXX this one is really in executor/spi.c */ | /* XXX this one is really in executor/spi.c */ | ||||||
| extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc, | extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc, | ||||||
|  | |||||||
| @ -7,30 +7,13 @@ | |||||||
|  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group |  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group | ||||||
|  * Portions Copyright (c) 1994, Regents of the University of California |  * Portions Copyright (c) 1994, Regents of the University of California | ||||||
|  * |  * | ||||||
|  * $Id: execdefs.h,v 1.11 2001/11/05 17:46:33 momjian Exp $ |  * $Id: execdefs.h,v 1.12 2002/02/27 19:35:51 tgl Exp $ | ||||||
|  * |  * | ||||||
|  *------------------------------------------------------------------------- |  *------------------------------------------------------------------------- | ||||||
|  */ |  */ | ||||||
| #ifndef EXECDEFS_H | #ifndef EXECDEFS_H | ||||||
| #define EXECDEFS_H | #define EXECDEFS_H | ||||||
| 
 | 
 | ||||||
| /* ----------------
 |  | ||||||
|  *		ExecutePlan() tuplecount definitions |  | ||||||
|  * ---------------- |  | ||||||
|  */ |  | ||||||
| #define ALL_TUPLES				0		/* return all tuples */ |  | ||||||
| #define ONE_TUPLE				1		/* return only one tuple */ |  | ||||||
| 
 |  | ||||||
| /* ----------------
 |  | ||||||
|  *		constants used by ExecMain |  | ||||||
|  * ---------------- |  | ||||||
|  */ |  | ||||||
| #define EXEC_RUN						3 |  | ||||||
| #define EXEC_FOR						4 |  | ||||||
| #define EXEC_BACK						5 |  | ||||||
| #define EXEC_RETONE						6 |  | ||||||
| #define EXEC_RESULT						7 |  | ||||||
| 
 |  | ||||||
| /* ----------------
 | /* ----------------
 | ||||||
|  *		Merge Join states |  *		Merge Join states | ||||||
|  * ---------------- |  * ---------------- | ||||||
|  | |||||||
| @ -8,7 +8,7 @@ | |||||||
|  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group |  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group | ||||||
|  * Portions Copyright (c) 1994, Regents of the University of California |  * Portions Copyright (c) 1994, Regents of the University of California | ||||||
|  * |  * | ||||||
|  * $Id: execdesc.h,v 1.17 2001/11/05 17:46:33 momjian Exp $ |  * $Id: execdesc.h,v 1.18 2002/02/27 19:35:54 tgl Exp $ | ||||||
|  * |  * | ||||||
|  *------------------------------------------------------------------------- |  *------------------------------------------------------------------------- | ||||||
|  */ |  */ | ||||||
| @ -19,6 +19,7 @@ | |||||||
| #include "nodes/plannodes.h" | #include "nodes/plannodes.h" | ||||||
| #include "tcop/dest.h" | #include "tcop/dest.h" | ||||||
| 
 | 
 | ||||||
|  | 
 | ||||||
| /* ----------------
 | /* ----------------
 | ||||||
|  *		query descriptor: |  *		query descriptor: | ||||||
|  *	a QueryDesc encapsulates everything that the executor |  *	a QueryDesc encapsulates everything that the executor | ||||||
| @ -31,10 +32,14 @@ typedef struct QueryDesc | |||||||
| 	Query	   *parsetree; | 	Query	   *parsetree; | ||||||
| 	Plan	   *plantree; | 	Plan	   *plantree; | ||||||
| 	CommandDest dest;			/* the destination output of the execution */ | 	CommandDest dest;			/* the destination output of the execution */ | ||||||
|  | 	const char *portalName;		/* name of portal, or NULL */ | ||||||
|  | 
 | ||||||
|  | 	TupleDesc	tupDesc;		/* set by ExecutorStart */ | ||||||
| } QueryDesc; | } QueryDesc; | ||||||
| 
 | 
 | ||||||
| /* in pquery.c */ | /* in pquery.c */ | ||||||
| extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree, | extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree, | ||||||
| 				CommandDest dest); | 								  CommandDest dest, const char *portalName); | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| #endif   /* EXECDESC_H  */ | #endif   /* EXECDESC_H  */ | ||||||
|  | |||||||
| @ -7,7 +7,7 @@ | |||||||
|  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group |  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group | ||||||
|  * Portions Copyright (c) 1994, Regents of the University of California |  * Portions Copyright (c) 1994, Regents of the University of California | ||||||
|  * |  * | ||||||
|  * $Id: executor.h,v 1.62 2002/02/19 20:11:19 tgl Exp $ |  * $Id: executor.h,v 1.63 2002/02/27 19:35:59 tgl Exp $ | ||||||
|  * |  * | ||||||
|  *------------------------------------------------------------------------- |  *------------------------------------------------------------------------- | ||||||
|  */ |  */ | ||||||
| @ -50,7 +50,7 @@ extern HeapTuple ExecRemoveJunk(JunkFilter *junkfilter, TupleTableSlot *slot); | |||||||
|  */ |  */ | ||||||
| extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate); | extern TupleDesc ExecutorStart(QueryDesc *queryDesc, EState *estate); | ||||||
| extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate, | extern TupleTableSlot *ExecutorRun(QueryDesc *queryDesc, EState *estate, | ||||||
| 			int feature, long count); | 								   ScanDirection direction, long count); | ||||||
| extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate); | extern void ExecutorEnd(QueryDesc *queryDesc, EState *estate); | ||||||
| extern void ExecConstraints(char *caller, ResultRelInfo *resultRelInfo, | extern void ExecConstraints(char *caller, ResultRelInfo *resultRelInfo, | ||||||
| 				TupleTableSlot *slot, EState *estate); | 				TupleTableSlot *slot, EState *estate); | ||||||
|  | |||||||
| @ -1,11 +1,13 @@ | |||||||
| /*-------------------------------------------------------------------------
 | /*-------------------------------------------------------------------------
 | ||||||
|  * |  * | ||||||
|  * dest.h |  * dest.h | ||||||
|  *		Whenever the backend executes a query, the results |  *	  support for communication destinations | ||||||
|  *		have to go someplace. |  * | ||||||
|  |  * Whenever the backend executes a query, the results | ||||||
|  |  * have to go someplace. | ||||||
|  * |  * | ||||||
|  *	  - stdout is the destination only when we are running a |  *	  - stdout is the destination only when we are running a | ||||||
|  *		backend without a postmaster and are returning results |  *		standalone backend (no postmaster) and are returning results | ||||||
|  *		back to an interactive user. |  *		back to an interactive user. | ||||||
|  * |  * | ||||||
|  *	  - a remote process is the destination when we are |  *	  - a remote process is the destination when we are | ||||||
| @ -14,15 +16,21 @@ | |||||||
|  *		to the frontend via the functions in backend/libpq. |  *		to the frontend via the functions in backend/libpq. | ||||||
|  * |  * | ||||||
|  *	  - None is the destination when the system executes |  *	  - None is the destination when the system executes | ||||||
|  *		a query internally.  This is not used now but it may be |  *		a query internally.  The results are discarded. | ||||||
|  *		useful for the parallel optimiser/executor. |  | ||||||
|  * |  * | ||||||
|  * dest.c defines three functions that implement destination management: |  * dest.c defines three functions that implement destination management: | ||||||
|  * |  * | ||||||
|  * BeginCommand: initialize the destination. |  * BeginCommand: initialize the destination at start of command. | ||||||
|  * DestToFunction: return a pointer to a struct of destination-specific |  * DestToFunction: return a pointer to a struct of destination-specific | ||||||
|  * receiver functions. |  * receiver functions. | ||||||
|  * EndCommand: clean up the destination when output is complete. |  * EndCommand: clean up the destination at end of command. | ||||||
|  |  * | ||||||
|  |  * BeginCommand/EndCommand are executed once per received SQL query. | ||||||
|  |  * | ||||||
|  |  * DestToFunction, and the receiver functions it links to, are executed | ||||||
|  |  * each time we run the executor to produce tuples, which may occur | ||||||
|  |  * multiple times per received query (eg, due to additional queries produced | ||||||
|  |  * by rewrite rules). | ||||||
|  * |  * | ||||||
|  * The DestReceiver object returned by DestToFunction may be a statically |  * The DestReceiver object returned by DestToFunction may be a statically | ||||||
|  * allocated object (for destination types that require no local state) |  * allocated object (for destination types that require no local state) | ||||||
| @ -32,14 +40,11 @@ | |||||||
|  * by casting the DestReceiver* pointer passed to them. |  * by casting the DestReceiver* pointer passed to them. | ||||||
|  * The palloc'd object is pfree'd by the DestReceiver's cleanup function. |  * The palloc'd object is pfree'd by the DestReceiver's cleanup function. | ||||||
|  * |  * | ||||||
|  * XXX FIXME: the initialization and cleanup code that currently appears |  | ||||||
|  * in-line in BeginCommand and EndCommand probably should be moved out |  | ||||||
|  * to routines associated with each destination receiver type. |  | ||||||
|  * |  * | ||||||
|  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group |  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group | ||||||
|  * Portions Copyright (c) 1994, Regents of the University of California |  * Portions Copyright (c) 1994, Regents of the University of California | ||||||
|  * |  * | ||||||
|  * $Id: dest.h,v 1.29 2002/02/26 22:47:11 tgl Exp $ |  * $Id: dest.h,v 1.30 2002/02/27 19:36:13 tgl Exp $ | ||||||
|  * |  * | ||||||
|  *------------------------------------------------------------------------- |  *------------------------------------------------------------------------- | ||||||
|  */ |  */ | ||||||
| @ -80,18 +85,17 @@ struct _DestReceiver | |||||||
| { | { | ||||||
| 	/* Called for each tuple to be output: */ | 	/* Called for each tuple to be output: */ | ||||||
| 	void		(*receiveTuple) (HeapTuple tuple, TupleDesc typeinfo, | 	void		(*receiveTuple) (HeapTuple tuple, TupleDesc typeinfo, | ||||||
| 											 DestReceiver *self); | 								 DestReceiver *self); | ||||||
| 	/* Initialization and teardown: */ | 	/* Initialization and teardown: */ | ||||||
| 	void		(*setup) (DestReceiver *self, TupleDesc typeinfo); | 	void		(*setup) (DestReceiver *self, int operation, | ||||||
|  | 						  const char *portalName, TupleDesc typeinfo); | ||||||
| 	void		(*cleanup) (DestReceiver *self); | 	void		(*cleanup) (DestReceiver *self); | ||||||
| 	/* Private fields might appear beyond this point... */ | 	/* Private fields might appear beyond this point... */ | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /* The primary destination management functions */ | /* The primary destination management functions */ | ||||||
| 
 | 
 | ||||||
| extern void BeginCommand(char *pname, int operation, TupleDesc attinfo, | extern void BeginCommand(const char *commandTag, CommandDest dest); | ||||||
| 			 bool isIntoRel, bool isIntoPortal, char *tag, |  | ||||||
| 			 CommandDest dest); |  | ||||||
| extern DestReceiver *DestToFunction(CommandDest dest); | extern DestReceiver *DestToFunction(CommandDest dest); | ||||||
| extern void EndCommand(const char *commandTag, CommandDest dest); | extern void EndCommand(const char *commandTag, CommandDest dest); | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user