/*-------------------------------------------------------------------------
*
* printtup.c
- * Routines to print out tuples to the destination (binary or non-binary
- * portals, frontend/interactive backend, etc.).
+ * Routines to print out tuples to the destination (both frontend
+ * clients and interactive backends are supported here).
+ *
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- *
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "access/heapam.h"
#include "access/printtup.h"
#include "catalog/pg_type.h"
+#include "libpq/libpq.h"
#include "libpq/pqformat.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_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self);
static void printtup_cleanup(DestReceiver *self);
}
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
- * 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
* tuples at all to output.
* 2. Checking in printtup allows us to handle the case that the tuples
* change type midway through (although this probably can't happen in
* the current executor).
- * 3. Right now, ExecutorRun passes a NULL for typeinfo anyway :-(
* ----------------
*/
}
* showatts
* ----------------
*/
-void
-showatts(char *name, TupleDesc tupleDesc)
+static void
+showatts(const char *name, TupleDesc tupleDesc)
{
- int i;
int natts = tupleDesc->natts;
Form_pg_attribute *attinfo = tupleDesc->attrs;
+ int i;
puts(name);
for (i = 0; i < natts; ++i)
}
/* ----------------
- * 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
*
*
* 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
* some of the executor utility code such as "ExecTypeFromTL" should be
*
* (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
- * 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,
* not an OID.)
*
*
*
* 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
* The PerformAddAttribute() code, like most of the relation
QueryDesc *queryDesc;
EState *estate;
MemoryContext oldcontext;
+ ScanDirection direction;
CommandId savedId;
bool temp_desc = false;
*/
oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
+ queryDesc = PortalGetQueryDesc(portal);
+ estate = PortalGetState(portal);
+
/*
* If the requested destination is not the same as the query's
* original destination, make a temporary QueryDesc with the proper
* original dest. This is necessary since a FETCH command will pass
* dest = Remote, not knowing whether the cursor is binary or not.
*/
- queryDesc = PortalGetQueryDesc(portal);
- estate = PortalGetState(portal);
-
if (dest != queryDesc->dest &&
!(queryDesc->dest == RemoteInternal && dest == Remote))
{
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
* opened. This ensures that we see the same tuples throughout the
/*
* 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
- * 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
- * NULL once.) If it's OK to do the fetch, call the executor. Then,
- * update the atStart/atEnd state depending on the number of tuples
- * that were retrieved.
+ * NULL once.) Then call the executor (we must not skip this, because
+ * the destination needs to see a setup and shutdown even if no tuples
+ * are available). Finally, update the atStart/atEnd state depending
+ * on the number of tuples that were retrieved.
*/
if (forward)
{
- if (!portal->atEnd)
- {
- ExecutorRun(queryDesc, estate, EXEC_FOR, (long) count);
+ if (portal->atEnd)
+ direction = NoMovementScanDirection;
+ else
+ direction = ForwardScanDirection;
- 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 */
+ ExecutorRun(queryDesc, estate, direction, (long) count);
- if (completionTag)
- snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
- (dest == None) ? "MOVE" : "FETCH",
- estate->es_processed);
- }
+ 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
{
- if (!portal->atStart)
- {
- ExecutorRun(queryDesc, estate, EXEC_BACK, (long) count);
+ if (portal->atStart)
+ direction = NoMovementScanDirection;
+ else
+ direction = BackwardScanDirection;
- 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 */
+ ExecutorRun(queryDesc, estate, direction, (long) count);
- if (completionTag)
- snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
- (dest == None) ? "MOVE" : "FETCH",
- estate->es_processed);
- }
+ 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 */
}
+ /* 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.
*/
* query plan and ExecutorEnd() should always be called at the end of
* 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.
*
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* query plan
*
* 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
* to be used as the per-query context for the query plan. ExecutorRun()
queryDesc->plantree,
estate);
+ queryDesc->tupDesc = result;
+
return result;
}
*
* ExecutorStart must have been called already.
*
- * the different features supported are:
- * EXEC_RUN: retrieve all tuples in the forward direction
- * EXEC_FOR: retrieve 'count' number of tuples in the forward dir
- * 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
+ * If direction is NoMovementScanDirection then nothing is done
+ * except to start up/shut down the destination. Otherwise,
+ * we retrieve up to 'count' tuples in the specified direction.
*
* Note: count = 0 is interpreted as "no limit".
*
* ----------------------------------------------------------------
*/
TupleTableSlot *
-ExecutorRun(QueryDesc *queryDesc, EState *estate, int feature, long count)
+ExecutorRun(QueryDesc *queryDesc, EState *estate,
+ ScanDirection direction, long count)
{
CmdType operation;
Plan *plan;
- TupleTableSlot *result;
CommandDest dest;
DestReceiver *destfunc;
+ TupleTableSlot *result;
/*
* sanity checks
operation = queryDesc->operation;
plan = queryDesc->plantree;
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
- * 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.
+ * startup tuple receiver
*/
- (*destfunc->setup) (destfunc, (TupleDesc) NULL);
-
- switch (feature)
- {
- case EXEC_RUN:
- result = ExecutePlan(estate,
- plan,
- operation,
- count,
- 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;
+ estate->es_processed = 0;
+ estate->es_lastoid = InvalidOid;
- /*
- * 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;
+ destfunc = DestToFunction(dest);
+ (*destfunc->setup) (destfunc, (int) operation,
+ queryDesc->portalName, queryDesc->tupDesc);
- default:
- elog(DEBUG, "ExecutorRun: Unknown feature %d", feature);
- result = NULL;
- break;
- }
+ /*
+ * run plan
+ */
+ if (direction == NoMovementScanDirection)
+ result = NULL;
+ else
+ result = ExecutePlan(estate,
+ plan,
+ operation,
+ count,
+ direction,
+ destfunc);
+ /*
+ * shutdown receiver
+ */
(*destfunc->cleanup) (destfunc);
return result;
*
* processes the query plan to retrieve 'numberTuples' tuples in the
* 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
* of a RETRIEVE or NULL otherwise.
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
nextes->next = NULL;
nextes->status = F_EXEC_START;
- nextes->qd = CreateQueryDesc(queryTree,
- planTree,
- None);
+
+ nextes->qd = CreateQueryDesc(queryTree, planTree, None, NULL);
estate = CreateExecutorState();
if (nargs > 0)
static TupleTableSlot *
postquel_getnext(execution_state *es)
{
- int feature;
+ long count;
if (es->qd->operation == CMD_UTILITY)
{
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
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
queryTree->isBinary = false;
/* Create the QueryDesc object and the executor state */
- queryDesc = CreateQueryDesc(queryTree, planTree, SPI);
+ queryDesc = CreateQueryDesc(queryTree, planTree, SPI, NULL);
eState = CreateExecutorState();
/* If the plan has parameters, put them into the executor state */
else if (plan == NULL)
{
qdesc = CreateQueryDesc(queryTree, planTree,
- islastquery ? SPI : None);
+ islastquery ? SPI : None, NULL);
state = CreateExecutorState();
res = _SPI_pquery(qdesc, state, islastquery ? tcount : 0);
if (res < 0 || islastquery)
else
{
qdesc = CreateQueryDesc(queryTree, planTree,
- islastquery ? SPI : None);
+ islastquery ? SPI : None, NULL);
res = _SPI_pquery(qdesc, NULL, islastquery ? tcount : 0);
if (res < 0)
return res;
else
{
qdesc = CreateQueryDesc(queryTree, planTree,
- islastquery ? SPI : None);
+ islastquery ? SPI : None, NULL);
state = CreateExecutorState();
if (nargs > 0)
{
Query *parseTree = queryDesc->parsetree;
int operation = queryDesc->operation;
CommandDest dest = queryDesc->dest;
- TupleDesc tupdesc;
bool isRetrieveIntoPortal = false;
bool isRetrieveIntoRelation = false;
char *intoName = NULL;
if (state == NULL) /* plan preparation */
return res;
+
#ifdef SPI_EXECUTOR_STATS
if (ShowExecutorStats)
ResetUsage();
#endif
- tupdesc = ExecutorStart(queryDesc, state);
+
+ ExecutorStart(queryDesc, state);
/*
* Don't work currently --- need to rearrange callers so that we
if (isRetrieveIntoPortal)
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;
save_lastoid = state->es_lastoid;
QueryDesc *querydesc;
EState *estate;
MemoryContext oldcontext;
+ ScanDirection direction;
CommandId savedId;
CommandDest olddest;
/* Run the executor like PerformPortalFetch and remember states */
if (forward)
{
- if (!portal->atEnd)
- {
- ExecutorRun(querydesc, estate, EXEC_FOR, (long) count);
- _SPI_current->processed = estate->es_processed;
- if (estate->es_processed > 0)
- portal->atStart = false;
- if (count <= 0 || (int) estate->es_processed < count)
- portal->atEnd = true;
- }
+ if (portal->atEnd)
+ direction = NoMovementScanDirection;
+ else
+ direction = ForwardScanDirection;
+
+ ExecutorRun(querydesc, estate, direction, (long) count);
+
+ 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
{
- if (!portal->atStart)
- {
- ExecutorRun(querydesc, estate, EXEC_BACK, (long) count);
- _SPI_current->processed = estate->es_processed;
- if (estate->es_processed > 0)
- portal->atEnd = false;
- if (count <= 0 || estate->es_processed < count)
- portal->atStart = true;
- }
+ if (portal->atStart)
+ direction = NoMovementScanDirection;
+ else
+ direction = BackwardScanDirection;
+
+ ExecutorRun(querydesc, estate, direction, (long) count);
+
+ 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.
*/
/*-------------------------------------------------------------------------
*
* 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) 1994, Regents of the University of California
*
- *
* 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
- * BeginCommand - prepare destination for tuples of the given type
+ * BeginCommand - initialize the destination at start of command
* 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
* ReadyForQuery - tell dest that we are ready for a new query
*
* These routines do the appropriate work before and after
* tuples are returned by a query to keep the backend and the
* "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"
}
static void
-donothingSetup(DestReceiver *self, TupleDesc typeinfo)
+donothingSetup(DestReceiver *self, int operation,
+ const char *portalName, TupleDesc typeinfo)
{
}
donothingReceive, donothingSetup, donothingCleanup
};
static DestReceiver debugtupDR = {
- debugtup, donothingSetup, donothingCleanup
+ debugtup, debugSetup, donothingCleanup
};
static DestReceiver spi_printtupDR = {
spi_printtup, donothingSetup, donothingCleanup
};
/* ----------------
- * BeginCommand - prepare destination for tuples of the given type
+ * BeginCommand - initialize the destination at start of command
* ----------------
*/
void
-BeginCommand(char *pname,
- int operation,
- TupleDesc tupdesc,
- bool isIntoRel,
- bool isIntoPortal,
- char *tag,
- CommandDest dest)
+BeginCommand(const char *commandTag, CommandDest dest)
{
- Form_pg_attribute *attrs = tupdesc->attrs;
- 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;
- }
+ /* Nothing to do at present */
}
/* ----------------
return &spi_printtupDR;
case None:
- default:
return &donothingDR;
}
- /*
- * never gets here, but DECstation lint appears to be stupid...
- */
-
+ /* should never get here */
return &donothingDR;
}
/* ----------------
- * EndCommand - tell destination that query is complete
+ * EndCommand - clean up the destination at end of command
* ----------------
*/
void
*
*
* 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
* this is the "main" module of the postgres backend and
/* Transaction control statements need some special handling */
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
* COMMIT/ABORT. It is important that this test occur before we
/*
* 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,
* these must outlive the execution context).
*/
if (!IsUnderPostmaster)
{
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");
}
/*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
QueryDesc *
CreateQueryDesc(Query *parsetree,
Plan *plantree,
- CommandDest dest)
+ CommandDest dest,
+ const char *portalName)
{
QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
qd->parsetree = parsetree; /* parse tree */
qd->plantree = plantree; /* plan */
qd->dest = dest; /* output dest */
+ qd->portalName = portalName; /* name, if dest is a portal */
+ qd->tupDesc = NULL; /* until set by ExecutorStart */
+
return qd;
}
char *completionTag)
{
int operation = parsetree->commandType;
- bool isRetrieveIntoPortal;
- bool isRetrieveIntoRelation;
+ bool isRetrieveIntoPortal = false;
char *intoName = NULL;
Portal portal = NULL;
MemoryContext oldContext = NULL;
TupleDesc attinfo;
/*
- * initialize portal/into relation status
+ * Check for special-case destinations
*/
- isRetrieveIntoPortal = false;
- isRetrieveIntoRelation = false;
-
if (operation == CMD_SELECT)
{
if (parsetree->isPortal)
{
isRetrieveIntoPortal = true;
intoName = parsetree->into;
- if (parsetree->isBinary)
- {
- /*
- * For internal format portals, we change Remote
- * (externalized form) to RemoteInternal (internalized
- * form)
- */
+ /* If binary portal, switch to alternate output format */
+ if (dest == Remote && parsetree->isBinary)
dest = RemoteInternal;
- }
}
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;
}
}
/*
* Now we can create the QueryDesc object.
*/
- queryDesc = CreateQueryDesc(parsetree, plan, dest);
-
- /*
- * 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;
+ queryDesc = CreateQueryDesc(parsetree, plan, dest, intoName);
/*
* create a default executor 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
* FETCH command is received.
* Now we get to the important call to ExecutorRun() where we actually
* run the plan..
*/
- ExecutorRun(queryDesc, state, EXEC_RUN, 0L);
+ ExecutorRun(queryDesc, state, ForwardScanDirection, 0L);
/*
* Build command completion status string, if caller wants one.
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
* sees a
* fetch 1 from FOO
* 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
- * '(EXEC_FOR 1). The executor then runs the query and returns a single
+ * gets the planned query and then calls the executor with a count
+ * 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
* portal query until we see a "close". This means we have to be
* careful about memory management.
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
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,
- DestReceiver *self);
+ DestReceiver *self);
/* XXX this one is really in executor/spi.c */
extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc,
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* 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
#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
* ----------------
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "nodes/plannodes.h"
#include "tcop/dest.h"
+
/* ----------------
* query descriptor:
* a QueryDesc encapsulates everything that the executor
Query *parsetree;
Plan *plantree;
CommandDest dest; /* the destination output of the execution */
+ const char *portalName; /* name of portal, or NULL */
+
+ TupleDesc tupDesc; /* set by ExecutorStart */
} QueryDesc;
/* in pquery.c */
extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
- CommandDest dest);
+ CommandDest dest, const char *portalName);
+
#endif /* EXECDESC_H */
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* 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 $
*
*-------------------------------------------------------------------------
*/
*/
extern TupleDesc ExecutorStart(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 ExecConstraints(char *caller, ResultRelInfo *resultRelInfo,
TupleTableSlot *slot, EState *estate);
/*-------------------------------------------------------------------------
*
* dest.h
- * Whenever the backend executes a query, the results
- * have to go someplace.
+ * support for communication destinations
+ *
+ * Whenever the backend executes a query, the results
+ * have to go someplace.
*
* - 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.
*
* - a remote process is the destination when we are
* to the frontend via the functions in backend/libpq.
*
* - None is the destination when the system executes
- * a query internally. This is not used now but it may be
- * useful for the parallel optimiser/executor.
+ * a query internally. The results are discarded.
*
* 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
* 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
* allocated object (for destination types that require no local state)
* by casting the DestReceiver* pointer passed to them.
* 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) 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 $
*
*-------------------------------------------------------------------------
*/
{
/* Called for each tuple to be output: */
void (*receiveTuple) (HeapTuple tuple, TupleDesc typeinfo,
- DestReceiver *self);
+ DestReceiver *self);
/* Initialization and teardown: */
- void (*setup) (DestReceiver *self, TupleDesc typeinfo);
+ void (*setup) (DestReceiver *self, int operation,
+ const char *portalName, TupleDesc typeinfo);
void (*cleanup) (DestReceiver *self);
/* Private fields might appear beyond this point... */
};
/* The primary destination management functions */
-extern void BeginCommand(char *pname, int operation, TupleDesc attinfo,
- bool isIntoRel, bool isIntoPortal, char *tag,
- CommandDest dest);
+extern void BeginCommand(const char *commandTag, CommandDest dest);
extern DestReceiver *DestToFunction(CommandDest dest);
extern void EndCommand(const char *commandTag, CommandDest dest);