1
0
mirror of https://github.com/postgres/postgres.git synced 2025-04-25 21:42:33 +03: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:
Tom Lane 2002-02-27 19:36:13 +00:00
parent e22c9c4475
commit 6779c55c22
15 changed files with 266 additions and 361 deletions

View File

@ -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

View File

@ -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.)
* *

View File

@ -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.
*/ */

View File

@ -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.

View File

@ -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

View File

@ -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.
*/ */

View File

@ -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

View File

@ -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");
} }
/* /*

View File

@ -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.

View File

@ -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.

View File

@ -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,

View File

@ -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
* ---------------- * ----------------

View File

@ -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 */

View File

@ -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);

View File

@ -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);