Commit 6779c55c authored by Tom Lane's avatar Tom Lane

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.
parent e22c9c44
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* 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 @@ ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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 @@ ...@@ -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, ...@@ -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 @@ ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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,46 +182,48 @@ PerformPortalFetch(char *name, ...@@ -194,46 +182,48 @@ 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;
ExecutorRun(queryDesc, estate, direction, (long) count);
if (estate->es_processed > 0) if (estate->es_processed > 0)
portal->atStart = false; /* OK to back up now */ portal->atStart = false; /* OK to back up now */
if (count <= 0 || (int) estate->es_processed < count) if (count <= 0 || (int) estate->es_processed < count)
portal->atEnd = true; /* we retrieved 'em all */ portal->atEnd = true; /* we retrieved 'em all */
if (completionTag)
snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
(dest == None) ? "MOVE" : "FETCH",
estate->es_processed);
}
} }
else else
{ {
if (!portal->atStart) if (portal->atStart)
{ direction = NoMovementScanDirection;
ExecutorRun(queryDesc, estate, EXEC_BACK, (long) count); else
direction = BackwardScanDirection;
ExecutorRun(queryDesc, estate, direction, (long) count);
if (estate->es_processed > 0) if (estate->es_processed > 0)
portal->atEnd = false; /* OK to go forward now */ portal->atEnd = false; /* OK to go forward now */
if (count <= 0 || (int) estate->es_processed < count) if (count <= 0 || (int) estate->es_processed < count)
portal->atStart = true; /* we retrieved 'em all */ portal->atStart = true; /* we retrieved 'em all */
}
/* Return command status if wanted */
if (completionTag) if (completionTag)
snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u", snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
(dest == None) ? "MOVE" : "FETCH", (dest == None) ? "MOVE" : "FETCH",
estate->es_processed); estate->es_processed);
}
}
/* /*
* Restore outer command ID. * Restore outer command ID.
......
...@@ -19,7 +19,7 @@ ...@@ -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 @@ ...@@ -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); ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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);
estate->es_processed = 0;
estate->es_lastoid = InvalidOid;
/* /*
* FIXME: the dest setup function ought to be handed the tuple desc * startup tuple receiver
* 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); estate->es_processed = 0;
estate->es_lastoid = InvalidOid;
switch (feature)
{
case EXEC_RUN:
result = ExecutePlan(estate,
plan,
operation,
count,
ForwardScanDirection,
destfunc);
break;
case EXEC_FOR: destfunc = DestToFunction(dest);
result = ExecutePlan(estate, (*destfunc->setup) (destfunc, (int) operation,
plan, queryDesc->portalName, queryDesc->tupDesc);
operation,
count,
ForwardScanDirection,
destfunc);
break;
/* /*
* retrieve next n "backward" tuples * run plan
*/ */
case EXEC_BACK: if (direction == NoMovementScanDirection)
result = NULL;
else
result = ExecutePlan(estate, result = ExecutePlan(estate,
plan, plan,
operation, operation,
count, count,
BackwardScanDirection, direction,
destfunc); destfunc);
break;
/* /*
* return one tuple but don't "retrieve" it. (this is used by * shutdown receiver
* 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;
}
(*destfunc->cleanup) (destfunc); (*destfunc->cleanup) (destfunc);
return result; return result;
...@@ -916,7 +880,7 @@ EndPlan(Plan *plan, EState *estate) ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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 @@ ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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;
ExecutorRun(querydesc, estate, direction, (long) count);
if (estate->es_processed > 0) if (estate->es_processed > 0)
portal->atStart = false; portal->atStart = false; /* OK to back up now */
if (count <= 0 || (int) estate->es_processed < count) if (count <= 0 || (int) estate->es_processed < count)
portal->atEnd = true; 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;
ExecutorRun(querydesc, estate, direction, (long) count);
if (estate->es_processed > 0) if (estate->es_processed > 0)
portal->atEnd = false; portal->atEnd = false; /* OK to go forward now */
if (count <= 0 || estate->es_processed < count) if (count <= 0 || (int) estate->es_processed < count)
portal->atStart = true; portal->atStart = true; /* we retrieved 'em all */
}
} }
_SPI_current->processed = estate->es_processed;
/* /*
* Restore outer command ID. * Restore outer command ID.
*/ */
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* 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 @@ ...@@ -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) ...@@ -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 = { ...@@ -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) ...@@ -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 @@ ...@@ -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 */ ...@@ -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 */ ...@@ -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) ...@@ -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 @@ ...@@ -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 @@ ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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,7 +18,8 @@ ...@@ -18,7 +18,8 @@
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);
......
...@@ -7,30 +7,13 @@ ...@@ -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 @@ ...@@ -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 @@ ...@@ -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 ...@@ -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 @@ ...@@ -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); ...@@ -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);
......
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* dest.h * dest.h
* support for communication destinations
*
* Whenever the backend executes a query, the results * Whenever the backend executes a query, the results
* have to go someplace. * 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 @@ ...@@ -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 @@ ...@@ -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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -82,16 +87,15 @@ struct _DestReceiver ...@@ -82,16 +87,15 @@ struct _DestReceiver
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);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment