*
* printtup.c
* Routines to print out tuples to the destination (both frontend
- * clients and interactive backends are supported here).
+ * clients and standalone backends are supported here).
*
*
* Portions Copyright (c) 1996-2002, 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.69 2003/05/06 00:20:31 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.70 2003/05/06 20:26:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/lsyscache.h"
-static void printtup_setup(DestReceiver *self, int operation,
+static void printtup_startup(DestReceiver *self, int operation,
const char *portalName, TupleDesc typeinfo, List *targetlist);
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_shutdown(DestReceiver *self);
+static void printtup_destroy(DestReceiver *self);
+
/* ----------------------------------------------------------------
* printtup / debugtup support
* ----------------
*/
DestReceiver *
-printtup_create_DR(bool isBinary, bool sendDescrip)
+printtup_create_DR(CommandDest dest)
{
DR_printtup *self = (DR_printtup *) palloc(sizeof(DR_printtup));
+ bool isBinary;
+ bool sendDescrip;
+
+ switch (dest)
+ {
+ case Remote:
+ isBinary = false;
+ sendDescrip = true;
+ break;
+ case RemoteInternal:
+ isBinary = true;
+ sendDescrip = true;
+ break;
+ case RemoteExecute:
+ isBinary = false;
+ sendDescrip = false; /* no T message for Execute */
+ break;
+ case RemoteExecuteInternal:
+ isBinary = true;
+ sendDescrip = false; /* no T message for Execute */
+ break;
+
+ default:
+ elog(ERROR, "printtup_create_DR: unsupported dest");
+ return NULL;
+ }
self->pub.receiveTuple = isBinary ? printtup_internal : printtup;
- self->pub.setup = printtup_setup;
- self->pub.cleanup = printtup_cleanup;
+ self->pub.startup = printtup_startup;
+ self->pub.shutdown = printtup_shutdown;
+ self->pub.destroy = printtup_destroy;
+ self->pub.mydest = dest;
self->sendDescrip = sendDescrip;
}
static void
-printtup_setup(DestReceiver *self, int operation,
- const char *portalName, TupleDesc typeinfo, List *targetlist)
+printtup_startup(DestReceiver *self, int operation,
+ const char *portalName, TupleDesc typeinfo, List *targetlist)
{
DR_printtup *myState = (DR_printtup *) self;
}
/* ----------------
- * printtup_cleanup
+ * printtup_shutdown
* ----------------
*/
static void
-printtup_cleanup(DestReceiver *self)
+printtup_shutdown(DestReceiver *self)
{
DR_printtup *myState = (DR_printtup *) self;
if (myState->myinfo)
pfree(myState->myinfo);
- pfree(myState);
+ myState->myinfo = NULL;
+ myState->attrinfo = NULL;
+}
+
+/* ----------------
+ * printtup_destroy
+ * ----------------
+ */
+static void
+printtup_destroy(DestReceiver *self)
+{
+ pfree(self);
}
/* ----------------
}
/* ----------------
- * debugSetup - prepare to print tuples for an interactive backend
+ * debugStartup - prepare to print tuples for an interactive backend
* ----------------
*/
void
-debugSetup(DestReceiver *self, int operation,
- const char *portalName, TupleDesc typeinfo, List *targetlist)
+debugStartup(DestReceiver *self, int operation,
+ const char *portalName, TupleDesc typeinfo, List *targetlist)
{
/*
* show the return type of the tuples
* Portions Copyright (c) 1994-5, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.107 2003/05/06 00:20:31 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/explain.c,v 1.108 2003/05/06 20:26:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* execute an EXPLAIN command
*/
void
-ExplainQuery(ExplainStmt *stmt, CommandDest dest)
+ExplainQuery(ExplainStmt *stmt, DestReceiver *dest)
{
Query *query = stmt->query;
TupOutputState *tstate;
- TupleDesc tupdesc;
List *rewritten;
List *l;
- /* need a tuple descriptor representing a single TEXT column */
- tupdesc = CreateTemplateTupleDesc(1, false);
- TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
- TEXTOID, -1, 0, false);
-
/* prepare for projection of tuples */
- tstate = begin_tup_output_tupdesc(dest, tupdesc);
+ tstate = begin_tup_output_tupdesc(dest, ExplainResultDesc(stmt));
if (query->commandType == CMD_UTILITY)
{
}
/*
+ * ExplainResultDesc -
+ * construct the result tupledesc for an EXPLAIN
+ */
+TupleDesc
+ExplainResultDesc(ExplainStmt *stmt)
+{
+ TupleDesc tupdesc;
+
+ /* need a tuple descriptor representing a single TEXT column */
+ tupdesc = CreateTemplateTupleDesc(1, false);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "QUERY PLAN",
+ TEXTOID, -1, 0, false);
+ return tupdesc;
+}
+
+/*
* ExplainOneQuery -
* print out the execution plan for one query
*/
plan = planner(query, isCursor, cursorOptions);
/* Create a QueryDesc requesting no output */
- queryDesc = CreateQueryDesc(query, plan, None, NULL, NULL,
+ queryDesc = CreateQueryDesc(query, plan, None_Receiver, NULL, NULL,
stmt->analyze);
ExplainOnePlan(queryDesc, stmt, tstate);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.14 2003/05/05 00:44:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.15 2003/05/06 20:26:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include <limits.h>
-#include "miscadmin.h"
#include "commands/portalcmds.h"
#include "executor/executor.h"
+#include "executor/tstoreReceiver.h"
#include "optimizer/planner.h"
#include "rewrite/rewriteHandler.h"
#include "tcop/pquery.h"
* Execute SQL DECLARE CURSOR command.
*/
void
-PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest)
+PerformCursorOpen(DeclareCursorStmt *stmt)
{
List *rewritten;
Query *query;
*/
void
PerformPortalFetch(FetchStmt *stmt,
- CommandDest dest,
+ DestReceiver *dest,
char *completionTag)
{
+ DestReceiver *mydest = dest;
Portal portal;
long nprocessed;
}
/*
- * Adjust dest if needed. MOVE wants dest = None.
+ * Adjust dest if needed. MOVE wants destination None.
*
* If fetching from a binary cursor and the requested destination is
* Remote, change it to RemoteInternal. Note we do NOT change if the
* specification wins out over the cursor's type.
*/
if (stmt->ismove)
- dest = None;
- else if (dest == Remote && (portal->cursorOptions & CURSOR_OPT_BINARY))
- dest = RemoteInternal;
+ mydest = CreateDestReceiver(None);
+ else if (dest->mydest == Remote &&
+ (portal->cursorOptions & CURSOR_OPT_BINARY))
+ mydest = CreateDestReceiver(RemoteInternal);
/* Do it */
nprocessed = PortalRunFetch(portal,
stmt->direction,
stmt->howMany,
- dest);
+ mydest);
/* Return command status if wanted */
if (completionTag)
snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %ld",
stmt->ismove ? "MOVE" : "FETCH",
nprocessed);
+
+ /* Clean up if we created a local destination */
+ if (mydest != dest)
+ (mydest->destroy) (mydest);
}
/*
AssertArg(portal->cleanup == PortalCleanup);
/*
- * Delete tuplestore if present. (Note: portalmem.c is responsible
- * for removing holdContext.) We should do this even under error
- * conditions; since the tuplestore would have been using cross-
- * transaction storage, its temp files need to be explicitly deleted.
- */
- if (portal->holdStore)
- {
- MemoryContext oldcontext;
-
- oldcontext = MemoryContextSwitchTo(portal->holdContext);
- tuplestore_end(portal->holdStore);
- MemoryContextSwitchTo(oldcontext);
- portal->holdStore = NULL;
- }
- /*
* Shut down executor, if still running. We skip this during error
* abort, since other mechanisms will take care of releasing executor
* resources, and we can't be sure that ExecutorEnd itself wouldn't fail.
PersistHoldablePortal(Portal portal)
{
QueryDesc *queryDesc = PortalGetQueryDesc(portal);
- Portal saveCurrentPortal;
MemoryContext savePortalContext;
MemoryContext saveQueryContext;
MemoryContext oldcxt;
* inside the transaction that originally created it.
*/
Assert(portal->createXact == GetCurrentTransactionId());
- Assert(portal->holdStore == NULL);
Assert(queryDesc != NULL);
Assert(portal->portalReady);
Assert(!portal->portalDone);
/*
- * This context is used to store the tuple set.
- * Caller must have created it already.
+ * Caller must have created the tuplestore already.
*/
Assert(portal->holdContext != NULL);
- oldcxt = MemoryContextSwitchTo(portal->holdContext);
-
- /* XXX: Should SortMem be used for this? */
- portal->holdStore = tuplestore_begin_heap(true, true, SortMem);
+ Assert(portal->holdStore != NULL);
/*
- * Before closing down the executor, we must copy the tupdesc, since
- * it was created in executor memory. Note we are copying it into
- * the holdContext.
+ * Before closing down the executor, we must copy the tupdesc into
+ * long-term memory, since it was created in executor memory.
*/
+ oldcxt = MemoryContextSwitchTo(portal->holdContext);
+
portal->tupDesc = CreateTupleDescCopy(portal->tupDesc);
MemoryContextSwitchTo(oldcxt);
portal->portalActive = true;
/*
- * Set global portal and context pointers.
+ * Set global portal context pointers.
*/
- saveCurrentPortal = CurrentPortal;
- CurrentPortal = portal;
savePortalContext = PortalContext;
PortalContext = PortalGetHeapMemory(portal);
saveQueryContext = QueryContext;
*/
ExecutorRewind(queryDesc);
- /* Set the destination to output to the tuplestore */
- queryDesc->dest = Tuplestore;
+ /* Change the destination to output to the tuplestore */
+ queryDesc->dest = CreateTuplestoreDestReceiver(portal->holdStore,
+ portal->holdContext);
/* Fetch the result set into the tuplestore */
ExecutorRun(queryDesc, ForwardScanDirection, 0L);
+ (*queryDesc->dest->destroy) (queryDesc->dest);
+ queryDesc->dest = NULL;
+
/*
* Now shut down the inner executor.
*/
/* Mark portal not active */
portal->portalActive = false;
- CurrentPortal = saveCurrentPortal;
PortalContext = savePortalContext;
QueryContext = saveQueryContext;
* Copyright (c) 2002-2003, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.15 2003/05/05 00:44:55 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.16 2003/05/06 20:26:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* Implements the 'EXECUTE' utility statement.
*/
void
-ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
+ExecuteQuery(ExecuteStmt *stmt, DestReceiver *dest)
{
PreparedStatement *entry;
char *query_string;
*/
PortalStart(portal, paramLI);
- (void) PortalRun(portal, FETCH_ALL, outputDest, outputDest, NULL);
+ (void) PortalRun(portal, FETCH_ALL, dest, dest, NULL);
PortalDrop(portal, false);
{
QueryDesc *qdesc;
- /* Create a QueryDesc requesting no output */
- qdesc = CreateQueryDesc(query, plan, None, NULL,
- paramLI, stmt->analyze);
-
if (execstmt->into)
{
- if (qdesc->operation != CMD_SELECT)
+ if (query->commandType != CMD_SELECT)
elog(ERROR, "INTO clause specified for non-SELECT query");
+ /* Copy the query so we can modify it */
+ query = copyObject(query);
+
query->into = execstmt->into;
- qdesc->dest = None;
}
+ /* Create a QueryDesc requesting no output */
+ qdesc = CreateQueryDesc(query, plan, None_Receiver, NULL,
+ paramLI, stmt->analyze);
+
ExplainOnePlan(qdesc, stmt, tstate);
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/commands/schemacmds.c,v 1.8 2003/04/29 22:13:08 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/commands/schemacmds.c,v 1.9 2003/05/06 20:26:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* schemas should contain only utility stmts */
Assert(querytree->commandType == CMD_UTILITY);
/* do this step */
- ProcessUtility(querytree->utilityStmt, None, NULL);
+ ProcessUtility(querytree->utilityStmt, None_Receiver, NULL);
/* make sure later steps can see the object created here */
CommandCounterIncrement();
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.207 2003/05/06 00:20:31 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.208 2003/05/06 20:26:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
CmdType operation,
long numberTuples,
ScanDirection direction,
- DestReceiver *destfunc);
+ DestReceiver *dest);
static void ExecSelect(TupleTableSlot *slot,
- DestReceiver *destfunc,
+ DestReceiver *dest,
EState *estate);
static void ExecInsert(TupleTableSlot *slot, ItemPointer tupleid,
EState *estate);
{
EState *estate;
CmdType operation;
- CommandDest dest;
- DestReceiver *destfunc;
+ DestReceiver *dest;
TupleTableSlot *result;
MemoryContext oldcontext;
estate->es_processed = 0;
estate->es_lastoid = InvalidOid;
- destfunc = DestToFunction(dest);
- (*destfunc->setup) (destfunc, operation,
- queryDesc->portalName,
- queryDesc->tupDesc,
- queryDesc->planstate->plan->targetlist);
+ (*dest->startup) (dest, operation,
+ queryDesc->portalName,
+ queryDesc->tupDesc,
+ queryDesc->planstate->plan->targetlist);
/*
* run plan
operation,
count,
direction,
- destfunc);
+ dest);
/*
* shutdown receiver
*/
- (*destfunc->cleanup) (destfunc);
+ (*dest->shutdown) (dest);
MemoryContextSwitchTo(oldcontext);
CmdType operation,
long numberTuples,
ScanDirection direction,
- DestReceiver *destfunc)
+ DestReceiver *dest)
{
JunkFilter *junkfilter;
TupleTableSlot *slot;
{
case CMD_SELECT:
ExecSelect(slot, /* slot containing tuple */
- destfunc, /* destination's tuple-receiver
- * obj */
+ dest, /* destination's tuple-receiver obj */
estate);
result = slot;
break;
*/
static void
ExecSelect(TupleTableSlot *slot,
- DestReceiver *destfunc,
+ DestReceiver *dest,
EState *estate)
{
HeapTuple tuple;
/*
* insert the tuple into the "into relation"
+ *
+ * XXX this probably ought to be replaced by a separate destination
*/
if (estate->es_into_relation_descriptor != NULL)
{
}
/*
- * send the tuple to the front end (or the screen)
+ * send the tuple to the destination
*/
- (*destfunc->receiveTuple) (tuple, attrtype, destfunc);
+ (*dest->receiveTuple) (tuple, attrtype, dest);
IncrRetrieved();
(estate->es_processed)++;
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.64 2003/05/06 00:20:31 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execTuples.c,v 1.65 2003/05/06 20:26:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
return typeInfo;
}
+/* ----------------------------------------------------------------
+ * ExecCleanTypeFromTL
+ *
+ * Same as above, but resjunk columns are omitted from the result.
+ * ----------------------------------------------------------------
+ */
+TupleDesc
+ExecCleanTypeFromTL(List *targetList, bool hasoid)
+{
+ TupleDesc typeInfo;
+ List *tlitem;
+ int len;
+ int cleanresno;
+
+ /*
+ * allocate a new typeInfo
+ */
+ len = ExecCleanTargetListLength(targetList);
+ typeInfo = CreateTemplateTupleDesc(len, hasoid);
+
+ /*
+ * scan list, generate type info for each entry
+ */
+ cleanresno = 1;
+ foreach(tlitem, targetList)
+ {
+ TargetEntry *tle = lfirst(tlitem);
+ Resdom *resdom = tle->resdom;
+
+ if (resdom->resjunk)
+ continue;
+ TupleDescInitEntry(typeInfo,
+ cleanresno++,
+ resdom->resname,
+ resdom->restype,
+ resdom->restypmod,
+ 0,
+ false);
+ }
+
+ return typeInfo;
+}
+
/*
* TupleDescGetSlot - Initialize a slot based on the supplied tupledesc
*/
* Table Function capability. Currently used by EXPLAIN and SHOW ALL
*/
TupOutputState *
-begin_tup_output_tupdesc(CommandDest dest, TupleDesc tupdesc)
+begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc)
{
TupOutputState *tstate;
tstate = (TupOutputState *) palloc(sizeof(TupOutputState));
tstate->metadata = TupleDescGetAttInMetadata(tupdesc);
- tstate->destfunc = DestToFunction(dest);
+ tstate->dest = dest;
- (*tstate->destfunc->setup) (tstate->destfunc, (int) CMD_SELECT,
- NULL, tupdesc, NIL);
+ (*tstate->dest->startup) (tstate->dest, (int) CMD_SELECT,
+ NULL, tupdesc, NIL);
return tstate;
}
HeapTuple tuple = BuildTupleFromCStrings(tstate->metadata, values);
/* send the tuple to the receiver */
- (*tstate->destfunc->receiveTuple) (tuple,
- tstate->metadata->tupdesc,
- tstate->destfunc);
+ (*tstate->dest->receiveTuple) (tuple,
+ tstate->metadata->tupdesc,
+ tstate->dest);
/* clean up */
heap_freetuple(tuple);
}
if (eol)
*eol++ = '\0';
else
- eol = text +strlen(text);
+ eol = text + strlen(text);
do_tup_output(tstate, &text);
text = eol;
void
end_tup_output(TupOutputState *tstate)
{
- (*tstate->destfunc->cleanup) (tstate->destfunc);
+ (*tstate->dest->shutdown) (tstate->dest);
+ /* note that destroying the dest is not ours to do */
/* XXX worth cleaning up the attinmetadata? */
pfree(tstate);
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.63 2003/05/06 00:20:31 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/functions.c,v 1.64 2003/05/06 20:26:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
{
Assert(es->qd == NULL);
es->qd = CreateQueryDesc(es->query, es->plan,
- None, NULL,
+ None_Receiver, NULL,
fcache->paramLI, false);
/* Utility commands don't need Executor. */
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.95 2003/05/06 00:20:31 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/spi.c,v 1.96 2003/05/06 20:26:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
Datum *Values, const char *Nulls, int tcount);
static void _SPI_cursor_operation(Portal portal, bool forward, int count,
- CommandDest dest);
+ DestReceiver *dest);
static _SPI_plan *_SPI_copy_plan(_SPI_plan *plan, int location);
void
SPI_cursor_fetch(Portal portal, bool forward, int count)
{
- _SPI_cursor_operation(portal, forward, count, SPI);
+ _SPI_cursor_operation(portal, forward, count, CreateDestReceiver(SPI));
+ /* we know that the SPI receiver doesn't need a destroy call */
}
void
SPI_cursor_move(Portal portal, bool forward, int count)
{
- _SPI_cursor_operation(portal, forward, count, None);
+ _SPI_cursor_operation(portal, forward, count, None_Receiver);
}
/* =================== private functions =================== */
/*
- * spi_dest_setup
+ * spi_dest_startup
* Initialize to receive tuples from Executor into SPITupleTable
* of current SPI procedure
*/
void
-spi_dest_setup(DestReceiver *self, int operation,
- const char *portalName, TupleDesc typeinfo, List *targetlist)
+spi_dest_startup(DestReceiver *self, int operation,
+ const char *portalName, TupleDesc typeinfo, List *targetlist)
{
SPITupleTable *tuptable;
MemoryContext oldcxt;
* _SPI_connected
*/
if (_SPI_curid != _SPI_connected || _SPI_connected < 0)
- elog(FATAL, "SPI: improper call to spi_dest_setup");
+ elog(FATAL, "SPI: improper call to spi_dest_startup");
if (_SPI_current != &(_SPI_stack[_SPI_curid]))
- elog(FATAL, "SPI: stack corrupted in spi_dest_setup");
+ elog(FATAL, "SPI: stack corrupted in spi_dest_startup");
if (_SPI_current->tuptable != NULL)
- elog(FATAL, "SPI: improper call to spi_dest_setup");
+ elog(FATAL, "SPI: improper call to spi_dest_startup");
oldcxt = _SPI_procmem(); /* switch to procedure memory context */
Query *queryTree = (Query *) lfirst(query_list_item);
Plan *planTree;
QueryDesc *qdesc;
+ DestReceiver *dest;
planTree = pg_plan_query(queryTree);
plan_list = lappend(plan_list, planTree);
+ dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None);
if (queryTree->commandType == CMD_UTILITY)
{
if (IsA(queryTree->utilityStmt, CopyStmt))
res = SPI_OK_UTILITY;
if (plan == NULL)
{
- ProcessUtility(queryTree->utilityStmt, None, NULL);
+ ProcessUtility(queryTree->utilityStmt, dest, NULL);
CommandCounterIncrement();
}
}
else if (plan == NULL)
{
- qdesc = CreateQueryDesc(queryTree, planTree,
- queryTree->canSetTag ? SPI : None,
+ qdesc = CreateQueryDesc(queryTree, planTree, dest,
NULL, NULL, false);
res = _SPI_pquery(qdesc, true,
queryTree->canSetTag ? tcount : 0);
}
else
{
- qdesc = CreateQueryDesc(queryTree, planTree,
- queryTree->canSetTag ? SPI : None,
+ qdesc = CreateQueryDesc(queryTree, planTree, dest,
NULL, NULL, false);
res = _SPI_pquery(qdesc, false, 0);
if (res < 0)
Query *queryTree = (Query *) lfirst(query_list_item);
Plan *planTree;
QueryDesc *qdesc;
+ DestReceiver *dest;
planTree = lfirst(plan_list);
plan_list = lnext(plan_list);
+ dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None);
if (queryTree->commandType == CMD_UTILITY)
{
- ProcessUtility(queryTree->utilityStmt, None, NULL);
+ ProcessUtility(queryTree->utilityStmt, dest, NULL);
res = SPI_OK_UTILITY;
CommandCounterIncrement();
}
else
{
- qdesc = CreateQueryDesc(queryTree, planTree,
- queryTree->canSetTag ? SPI : None,
+ qdesc = CreateQueryDesc(queryTree, planTree, dest,
NULL, paramLI, false);
res = _SPI_pquery(qdesc, true,
queryTree->canSetTag ? tcount : 0);
if (queryDesc->parsetree->into != NULL) /* select into table */
{
res = SPI_OK_SELINTO;
- queryDesc->dest = None; /* don't output results anywhere */
+ queryDesc->dest = None_Receiver; /* don't output results */
}
break;
case CMD_INSERT:
_SPI_current->processed = queryDesc->estate->es_processed;
save_lastoid = queryDesc->estate->es_lastoid;
- if (operation == CMD_SELECT && queryDesc->dest == SPI)
+ if (operation == CMD_SELECT && queryDesc->dest->mydest == SPI)
{
if (_SPI_checktuples())
elog(FATAL, "SPI_select: # of processed tuples check failed");
}
- if (queryDesc->dest == SPI)
+ if (queryDesc->dest->mydest == SPI)
{
SPI_processed = _SPI_current->processed;
SPI_lastoid = save_lastoid;
*/
static void
_SPI_cursor_operation(Portal portal, bool forward, int count,
- CommandDest dest)
+ DestReceiver *dest)
{
/* Check that the portal is valid */
if (!PortalIsValid(portal))
(long) count,
dest);
- if (dest == SPI && _SPI_checktuples())
+ if (dest->mydest == SPI && _SPI_checktuples())
elog(FATAL, "SPI_fetch: # of processed tuples check failed");
/* Put the result into place for access by caller */
SPITupleTable *tuptable = _SPI_current->tuptable;
bool failed = false;
- if (tuptable == NULL) /* spi_dest_setup was not called */
+ if (tuptable == NULL) /* spi_dest_startup was not called */
failed = true;
else if (processed != (tuptable->alloced - tuptable->free))
failed = true;
/*-------------------------------------------------------------------------
*
- * tstore_receiver.c
+ * tstoreReceiver.c
* an implementation of DestReceiver that stores the result tuples in
* a Tuplestore
*
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/tstoreReceiver.c,v 1.4 2003/05/06 00:20:31 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/tstoreReceiver.c,v 1.5 2003/05/06 20:26:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "executor/tstoreReceiver.h"
-#include "utils/memutils.h"
-#include "utils/portal.h"
+
typedef struct
{
/*
* Prepare to receive tuples from executor.
- *
- * XXX: As currently implemented, this routine is a hack: there should
- * be no tie between this code and the portal system. Instead, the
- * receiver function that is part of DestFunction should be passed a
- * QueryDesc, so that the call site of ExecutorRun can "sub-class"
- * QueryDesc and pass in any necessary addition information (in this
- * case, the Tuplestore to use).
*/
static void
-tstoreSetupReceiver(DestReceiver *self, int operation,
- const char *portalname,
- TupleDesc typeinfo, List *targetlist)
+tstoreStartupReceiver(DestReceiver *self, int operation,
+ const char *portalname,
+ TupleDesc typeinfo, List *targetlist)
{
- TStoreState *myState = (TStoreState *) self;
-
- /* Should only be called within a suitably-prepped portal */
- if (CurrentPortal == NULL ||
- CurrentPortal->holdStore == NULL)
- elog(ERROR, "Tuplestore destination used in wrong context");
-
- /* Debug check: make sure portal's result tuple desc is correct */
- Assert(CurrentPortal->tupDesc != NULL);
- Assert(equalTupleDescs(CurrentPortal->tupDesc, typeinfo));
-
- myState->tstore = CurrentPortal->holdStore;
- myState->cxt = CurrentPortal->holdContext;
+ /* do nothing */
}
/*
}
/*
- * Clean up
+ * Clean up at end of an executor run
*/
static void
-tstoreCleanupReceiver(DestReceiver *self)
+tstoreShutdownReceiver(DestReceiver *self)
{
/* do nothing */
}
/*
+ * Destroy receiver when done with it
+ */
+static void
+tstoreDestroyReceiver(DestReceiver *self)
+{
+ pfree(self);
+}
+
+/*
* Initially create a DestReceiver object.
*/
DestReceiver *
-tstoreReceiverCreateDR(void)
+CreateTuplestoreDestReceiver(Tuplestorestate *tStore,
+ MemoryContext tContext)
{
TStoreState *self = (TStoreState *) palloc(sizeof(TStoreState));
self->pub.receiveTuple = tstoreReceiveTuple;
- self->pub.setup = tstoreSetupReceiver;
- self->pub.cleanup = tstoreCleanupReceiver;
+ self->pub.startup = tstoreStartupReceiver;
+ self->pub.shutdown = tstoreShutdownReceiver;
+ self->pub.destroy = tstoreDestroyReceiver;
+ self->pub.mydest = Tuplestore;
- self->tstore = NULL;
- self->cxt = NULL;
+ self->tstore = tStore;
+ self->cxt = tContext;
return (DestReceiver *) self;
}
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.56 2003/05/06 00:20:33 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.57 2003/05/06 20:26:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
* BeginCommand - initialize the destination at start of command
- * DestToFunction - identify per-tuple processing routines
+ * CreateDestReceiver - create tuple receiver object for destination
* 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
#include "access/printtup.h"
#include "access/xact.h"
-#include "executor/tstoreReceiver.h"
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
}
static void
-donothingSetup(DestReceiver *self, int operation,
- const char *portalName, TupleDesc typeinfo, List *targetlist)
+donothingStartup(DestReceiver *self, int operation,
+ const char *portalName, TupleDesc typeinfo, List *targetlist)
{
}
static void
donothingCleanup(DestReceiver *self)
{
+ /* this is used for both shutdown and destroy methods */
}
/* ----------------
* ----------------
*/
static DestReceiver donothingDR = {
- donothingReceive, donothingSetup, donothingCleanup
+ donothingReceive, donothingStartup, donothingCleanup, donothingCleanup,
+ None
};
static DestReceiver debugtupDR = {
- debugtup, debugSetup, donothingCleanup
+ debugtup, debugStartup, donothingCleanup, donothingCleanup,
+ Debug
};
static DestReceiver spi_printtupDR = {
- spi_printtup, spi_dest_setup, donothingCleanup
+ spi_printtup, spi_dest_startup, donothingCleanup, donothingCleanup,
+ SPI
};
+/* Globally available receiver for None */
+DestReceiver *None_Receiver = &donothingDR;
+
+
/* ----------------
* BeginCommand - initialize the destination at start of command
* ----------------
}
/* ----------------
- * DestToFunction - return appropriate receiver function set for dest
+ * CreateDestReceiver - return appropriate receiver function set for dest
* ----------------
*/
DestReceiver *
-DestToFunction(CommandDest dest)
+CreateDestReceiver(CommandDest dest)
{
switch (dest)
{
case Remote:
- return printtup_create_DR(false, true);
-
case RemoteInternal:
- return printtup_create_DR(true, true);
-
case RemoteExecute:
- /* like Remote, but suppress output of T message */
- return printtup_create_DR(false, false);
-
case RemoteExecuteInternal:
- return printtup_create_DR(true, false);
+ return printtup_create_DR(dest);
case None:
return &donothingDR;
return &spi_printtupDR;
case Tuplestore:
- return tstoreReceiverCreateDR();
+ /*
+ * This is disallowed, you must use tstoreReceiver.c's
+ * specialized function to create a Tuplestore DestReceiver
+ */
+ elog(ERROR, "CreateDestReceiver: cannot handle Tuplestore");
+ break;
}
/* should never get here */
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.335 2003/05/06 05:15:45 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.336 2003/05/06 20:26:27 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
static void
exec_simple_query(const char *query_string)
{
+ CommandDest dest = whereToSendOutput;
+ DestReceiver *receiver;
MemoryContext oldcontext;
List *parsetree_list,
*parsetree_item;
ResetUsage();
/*
+ * Create destination receiver object --- we can reuse it for all
+ * queries in the string. Note it is created in MessageContext.
+ */
+ receiver = CreateDestReceiver(dest);
+
+ /*
* Start up a transaction command. All queries generated by the
* query_string will be in this same command block, *unless* we find a
* BEGIN/COMMIT/ABORT statement; we have to force a new xact command
set_ps_display(commandTag);
- BeginCommand(commandTag, whereToSendOutput);
+ BeginCommand(commandTag, dest);
/*
* If we are in an aborted transaction, reject all commands except
(void) PortalRun(portal,
FETCH_ALL,
- whereToSendOutput,
- whereToSendOutput,
+ receiver,
+ receiver,
completionTag);
PortalDrop(portal, false);
* (But a command aborted by error will not send an EndCommand
* report at all.)
*/
- EndCommand(completionTag, whereToSendOutput);
+ EndCommand(completionTag, dest);
} /* end loop over parsetrees */
/*
* If there were no parsetrees, return EmptyQueryResponse message.
*/
if (!parsetree_list)
- NullCommand(whereToSendOutput);
+ NullCommand(dest);
+
+ (*receiver->destroy) (receiver);
QueryContext = NULL;
exec_execute_message(const char *portal_name, int is_binary, long max_rows)
{
CommandDest dest;
+ DestReceiver *receiver;
Portal portal;
bool is_trans_stmt = false;
bool is_trans_exit = false;
/*
* Okay to run the portal.
*/
+ receiver = CreateDestReceiver(dest);
+
if (max_rows <= 0)
max_rows = FETCH_ALL;
completed = PortalRun(portal,
max_rows,
- dest,
- dest,
+ receiver,
+ receiver,
completionTag);
+ (*receiver->destroy) (receiver);
+
if (completed)
{
if (is_trans_stmt)
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
- puts("$Revision: 1.335 $ $Date: 2003/05/06 05:15:45 $\n");
+ puts("$Revision: 1.336 $ $Date: 2003/05/06 20:26:27 $\n");
}
/*
*/
MemoryContextSwitchTo(TopMemoryContext);
MemoryContextResetAndDeleteChildren(ErrorContext);
- CurrentPortal = NULL;
PortalContext = NULL;
QueryContext = NULL;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.61 2003/05/06 00:20:33 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.62 2003/05/06 20:26:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "executor/executor.h"
+#include "executor/tstoreReceiver.h"
#include "miscadmin.h"
#include "tcop/tcopprot.h"
#include "tcop/pquery.h"
static uint32 RunFromStore(Portal portal, ScanDirection direction, long count,
- CommandDest dest);
+ DestReceiver *dest);
static long PortalRunSelect(Portal portal, bool forward, long count,
- CommandDest dest);
+ DestReceiver *dest);
static void PortalRunUtility(Portal portal, Query *query,
- CommandDest dest, char *completionTag);
+ DestReceiver *dest, char *completionTag);
static void PortalRunMulti(Portal portal,
- CommandDest dest, CommandDest altdest,
+ DestReceiver *dest, DestReceiver *altdest,
char *completionTag);
static long DoPortalRunFetch(Portal portal,
FetchDirection fdirection,
long count,
- CommandDest dest);
+ DestReceiver *dest);
static void DoPortalRewind(Portal portal);
QueryDesc *
CreateQueryDesc(Query *parsetree,
Plan *plantree,
- CommandDest dest,
+ DestReceiver *dest,
const char *portalName,
ParamListInfo params,
bool doInstrument)
Plan *plan,
ParamListInfo params,
const char *portalName,
- CommandDest dest,
+ DestReceiver *dest,
char *completionTag)
{
int operation = parsetree->commandType;
* special-cases this case. (Perhaps would be cleaner to have
* an additional destination type?)
*/
- dest = None;
+ dest = None_Receiver;
}
}
FreeQueryDesc(queryDesc);
}
+/*
+ * ChoosePortalStrategy
+ * Select portal execution strategy given the intended query list.
+ *
+ * See the comments in portal.h.
+ */
+PortalStrategy
+ChoosePortalStrategy(List *parseTrees)
+{
+ PortalStrategy strategy;
+
+ strategy = PORTAL_MULTI_QUERY; /* default assumption */
+
+ if (length(parseTrees) == 1)
+ {
+ Query *query = (Query *) lfirst(parseTrees);
+
+ if (query->commandType == CMD_SELECT &&
+ query->canSetTag &&
+ query->into == NULL)
+ {
+ strategy = PORTAL_ONE_SELECT;
+ }
+ else if (query->commandType == CMD_UTILITY &&
+ query->canSetTag &&
+ query->utilityStmt != NULL)
+ {
+ if (UtilityReturnsTuples(query->utilityStmt))
+ strategy = PORTAL_UTIL_SELECT;
+ }
+ }
+ return strategy;
+}
/*
* PortalStart
PortalStart(Portal portal, ParamListInfo params)
{
MemoryContext oldContext;
- Query *query = NULL;
QueryDesc *queryDesc;
AssertArg(PortalIsValid(portal));
portal->portalParams = params;
/*
- * Determine the portal execution strategy (see comments in portal.h)
+ * Determine the portal execution strategy
*/
- portal->strategy = PORTAL_MULTI_QUERY; /* default assumption */
- if (length(portal->parseTrees) == 1)
- {
- query = (Query *) lfirst(portal->parseTrees);
- if (query->commandType == CMD_SELECT &&
- query->canSetTag &&
- query->into == NULL)
- portal->strategy = PORTAL_ONE_SELECT;
- else if (query->commandType == CMD_UTILITY &&
- query->canSetTag &&
- query->utilityStmt != NULL)
- {
- /* XXX check for things that can be PORTAL_UTIL_SELECT */
- }
- }
+ portal->strategy = ChoosePortalStrategy(portal->parseTrees);
/*
* Fire her up according to the strategy
* Create QueryDesc in portal's context; for the moment, set
* the destination to None.
*/
- queryDesc = CreateQueryDesc(query,
+ queryDesc = CreateQueryDesc((Query *) lfirst(portal->parseTrees),
(Plan *) lfirst(portal->planTrees),
- None,
+ None_Receiver,
portal->name,
params,
false);
* This tells PortalCleanup to shut down the executor
*/
portal->queryDesc = queryDesc;
+ /*
+ * Remember tuple descriptor
+ */
portal->tupDesc = queryDesc->tupDesc;
/*
* Reset cursor position data to "start of query"
break;
case PORTAL_UTIL_SELECT:
- /* XXX implement later */
- /* XXX query snapshot here? no, RunUtility will do it */
- /* xxx what about Params? */
- portal->tupDesc = NULL;
+ /*
+ * We don't set query snapshot here, because PortalRunUtility
+ * will take care of it.
+ */
+ portal->tupDesc =
+ UtilityTupleDescriptor(((Query *) lfirst(portal->parseTrees))->utilityStmt);
+ /*
+ * Reset cursor position data to "start of query"
+ */
+ portal->atStart = true;
+ portal->atEnd = false; /* allow fetches */
+ portal->portalPos = 0;
+ portal->posOverflow = false;
break;
case PORTAL_MULTI_QUERY:
* suspended due to exhaustion of the count parameter.
*/
bool
-PortalRun(Portal portal, long count, CommandDest dest, CommandDest altdest,
+PortalRun(Portal portal, long count,
+ DestReceiver *dest, DestReceiver *altdest,
char *completionTag)
{
bool result;
- Portal saveCurrentPortal;
MemoryContext savePortalContext;
MemoryContext saveQueryContext;
MemoryContext oldContext;
portal->portalActive = true;
/*
- * Set global portal and context pointers.
+ * Set global portal context pointers.
*/
- saveCurrentPortal = CurrentPortal;
- CurrentPortal = portal;
savePortalContext = PortalContext;
PortalContext = PortalGetHeapMemory(portal);
saveQueryContext = QueryContext;
*/
if (!portal->portalUtilReady)
{
+ DestReceiver *treceiver;
+
+ PortalCreateHoldStore(portal);
+ treceiver = CreateTuplestoreDestReceiver(portal->holdStore,
+ portal->holdContext);
PortalRunUtility(portal, lfirst(portal->parseTrees),
- Tuplestore, NULL);
+ treceiver, NULL);
+ (*treceiver->destroy) (treceiver);
portal->portalUtilReady = true;
}
/*
/* Mark portal not active */
portal->portalActive = false;
- CurrentPortal = saveCurrentPortal;
PortalContext = savePortalContext;
QueryContext = saveQueryContext;
PortalRunSelect(Portal portal,
bool forward,
long count,
- CommandDest dest)
+ DestReceiver *dest)
{
QueryDesc *queryDesc;
ScanDirection direction;
*/
static uint32
RunFromStore(Portal portal, ScanDirection direction, long count,
- CommandDest dest)
+ DestReceiver *dest)
{
- DestReceiver *destfunc;
List *targetlist;
long current_tuple_count = 0;
- destfunc = DestToFunction(dest);
-
if (portal->strategy == PORTAL_ONE_SELECT)
targetlist = ((Plan *) lfirst(portal->planTrees))->targetlist;
else
targetlist = NIL;
- (*destfunc->setup) (destfunc, CMD_SELECT, portal->name, portal->tupDesc,
- targetlist);
+ (*dest->startup) (dest, CMD_SELECT, portal->name, portal->tupDesc,
+ targetlist);
if (direction == NoMovementScanDirection)
{
if (tup == NULL)
break;
- (*destfunc->receiveTuple) (tup, portal->tupDesc, destfunc);
+ (*dest->receiveTuple) (tup, portal->tupDesc, dest);
if (should_free)
pfree(tup);
}
}
- (*destfunc->cleanup) (destfunc);
+ (*dest->shutdown) (dest);
return (uint32) current_tuple_count;
}
*/
static void
PortalRunUtility(Portal portal, Query *query,
- CommandDest dest, char *completionTag)
+ DestReceiver *dest, char *completionTag)
{
Node *utilityStmt = query->utilityStmt;
*/
static void
PortalRunMulti(Portal portal,
- CommandDest dest, CommandDest altdest,
+ DestReceiver *dest, DestReceiver *altdest,
char *completionTag)
{
List *plantree_list = portal->planTrees;
PortalRunFetch(Portal portal,
FetchDirection fdirection,
long count,
- CommandDest dest)
+ DestReceiver *dest)
{
long result;
- Portal saveCurrentPortal;
MemoryContext savePortalContext;
MemoryContext saveQueryContext;
MemoryContext oldContext;
portal->portalActive = true;
/*
- * Set global portal and context pointers.
+ * Set global portal context pointers.
*/
- saveCurrentPortal = CurrentPortal;
- CurrentPortal = portal;
savePortalContext = PortalContext;
PortalContext = PortalGetHeapMemory(portal);
saveQueryContext = QueryContext;
/* Mark portal not active */
portal->portalActive = false;
- CurrentPortal = saveCurrentPortal;
PortalContext = savePortalContext;
QueryContext = saveQueryContext;
DoPortalRunFetch(Portal portal,
FetchDirection fdirection,
long count,
- CommandDest dest)
+ DestReceiver *dest)
{
bool forward;
{
DoPortalRewind(portal);
if (count > 1)
- PortalRunSelect(portal, true, count-1, None);
+ PortalRunSelect(portal, true, count-1,
+ None_Receiver);
}
else
{
if (portal->atEnd)
pos++; /* need one extra fetch if off end */
if (count <= pos)
- PortalRunSelect(portal, false, pos-count+1, None);
+ PortalRunSelect(portal, false, pos-count+1,
+ None_Receiver);
else if (count > pos+1)
- PortalRunSelect(portal, true, count-pos-1, None);
+ PortalRunSelect(portal, true, count-pos-1,
+ None_Receiver);
}
return PortalRunSelect(portal, true, 1L, dest);
}
* (Is it worth considering case where count > half of size
* of query? We could rewind once we know the size ...)
*/
- PortalRunSelect(portal, true, FETCH_ALL, None);
+ PortalRunSelect(portal, true, FETCH_ALL, None_Receiver);
if (count < -1)
- PortalRunSelect(portal, false, -count-1, None);
+ PortalRunSelect(portal, false, -count-1, None_Receiver);
return PortalRunSelect(portal, false, 1L, dest);
}
else /* count == 0 */
* Definition: advance count-1 rows, return next row (if any).
*/
if (count > 1)
- PortalRunSelect(portal, true, count-1, None);
+ PortalRunSelect(portal, true, count-1, None_Receiver);
return PortalRunSelect(portal, true, 1L, dest);
}
else if (count < 0)
* (if any).
*/
if (count < -1)
- PortalRunSelect(portal, false, -count-1, None);
+ PortalRunSelect(portal, false, -count-1, None_Receiver);
return PortalRunSelect(portal, false, 1L, dest);
}
else /* count == 0 */
/* Are we sitting on a row? */
on_row = (!portal->atStart && !portal->atEnd);
- if (dest == None)
+ if (dest->mydest == None)
{
/* MOVE 0 returns 0/1 based on if FETCH 0 would return a row */
return on_row ? 1L : 0L;
*/
if (on_row)
{
- PortalRunSelect(portal, false, 1L, None);
+ PortalRunSelect(portal, false, 1L, None_Receiver);
/* Set up to fetch one row forward */
count = 1;
forward = true;
/*
* Optimize MOVE BACKWARD ALL into a Rewind.
*/
- if (!forward && count == FETCH_ALL && dest == None)
+ if (!forward && count == FETCH_ALL && dest->mydest == None)
{
long result = portal->portalPos;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.198 2003/05/02 20:54:35 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.199 2003/05/06 20:26:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "parser/parse_type.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteRemove.h"
+#include "tcop/pquery.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/guc.h"
*/
void
ProcessUtility(Node *parsetree,
- CommandDest dest,
+ DestReceiver *dest,
char *completionTag)
{
check_xact_readonly(parsetree);
* Portal (cursor) manipulation
*/
case T_DeclareCursorStmt:
- PerformCursorOpen((DeclareCursorStmt *) parsetree, dest);
+ PerformCursorOpen((DeclareCursorStmt *) parsetree);
break;
case T_ClosePortalStmt:
{
VariableShowStmt *n = (VariableShowStmt *) parsetree;
- GetPGVariable(n->name);
+ GetPGVariable(n->name, dest);
}
break;
}
}
+/*
+ * UtilityReturnsTuples
+ * Return "true" if this utility statement will send output to the
+ * destination.
+ *
+ * Generally, there should be a case here for each case in ProcessUtility
+ * where "dest" is passed on.
+ */
+bool
+UtilityReturnsTuples(Node *parsetree)
+{
+ switch (nodeTag(parsetree))
+ {
+ case T_FetchStmt:
+ {
+ FetchStmt *stmt = (FetchStmt *) parsetree;
+ Portal portal;
+
+ if (stmt->ismove)
+ return false;
+ portal = GetPortalByName(stmt->portalname);
+ if (!PortalIsValid(portal))
+ return false; /* not our business to raise error */
+ /*
+ * Note: if portal contains multiple statements then it's
+ * possible some of them will return tuples, but we don't
+ * handle that case here.
+ */
+ return portal->tupDesc ? true : false;
+ }
+
+ case T_ExecuteStmt:
+ {
+ ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
+ PreparedStatement *entry;
+
+ if (stmt->into)
+ return false;
+ entry = FetchPreparedStatement(stmt->name, false);
+ if (!entry)
+ return false; /* not our business to raise error */
+ switch (ChoosePortalStrategy(entry->query_list))
+ {
+ case PORTAL_ONE_SELECT:
+ return true;
+ case PORTAL_UTIL_SELECT:
+ return true;
+ case PORTAL_MULTI_QUERY:
+ /* can't figure it out, per note above */
+ break;
+ }
+ return false;
+ }
+
+ case T_ExplainStmt:
+ return true;
+
+ case T_VariableShowStmt:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/*
+ * UtilityTupleDescriptor
+ * Fetch the actual output tuple descriptor for a utility statement
+ * for which UtilityReturnsTuples() previously returned "true".
+ *
+ * The returned descriptor is created in (or copied into) the current memory
+ * context.
+ */
+TupleDesc
+UtilityTupleDescriptor(Node *parsetree)
+{
+ switch (nodeTag(parsetree))
+ {
+ case T_FetchStmt:
+ {
+ FetchStmt *stmt = (FetchStmt *) parsetree;
+ Portal portal;
+
+ if (stmt->ismove)
+ return NULL;
+ portal = GetPortalByName(stmt->portalname);
+ if (!PortalIsValid(portal))
+ return NULL; /* not our business to raise error */
+ return CreateTupleDescCopy(portal->tupDesc);
+ }
+
+ case T_ExecuteStmt:
+ {
+ ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
+ PreparedStatement *entry;
+ Query *query;
+
+ if (stmt->into)
+ return NULL;
+ entry = FetchPreparedStatement(stmt->name, false);
+ if (!entry)
+ return NULL; /* not our business to raise error */
+ switch (ChoosePortalStrategy(entry->query_list))
+ {
+ case PORTAL_ONE_SELECT:
+ query = (Query *) lfirst(entry->query_list);
+ return ExecCleanTypeFromTL(query->targetList, false);
+ case PORTAL_UTIL_SELECT:
+ query = (Query *) lfirst(entry->query_list);
+ return UtilityTupleDescriptor(query->utilityStmt);
+ case PORTAL_MULTI_QUERY:
+ break;
+ }
+ return NULL;
+ }
+
+ case T_ExplainStmt:
+ return ExplainResultDesc((ExplainStmt *) parsetree);
+
+ case T_VariableShowStmt:
+ {
+ VariableShowStmt *n = (VariableShowStmt *) parsetree;
+
+ return GetPGVariableResultDesc(n->name);
+ }
+
+ default:
+ return NULL;
+ }
+}
+
/*
* CreateCommandTag
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.122 2003/05/02 22:02:47 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/misc/guc.c,v 1.123 2003/05/06 20:26:27 tgl Exp $
*
*--------------------------------------------------------------------
*/
* SHOW command
*/
void
-GetPGVariable(const char *name)
+GetPGVariable(const char *name, DestReceiver *dest)
{
if (strcasecmp(name, "all") == 0)
- ShowAllGUCConfig();
+ ShowAllGUCConfig(dest);
else
- ShowGUCConfigOption(name);
+ ShowGUCConfigOption(name, dest);
+}
+
+TupleDesc
+GetPGVariableResultDesc(const char *name)
+{
+ TupleDesc tupdesc;
+
+ if (strcasecmp(name, "all") == 0)
+ {
+ /* need a tuple descriptor representing two TEXT columns */
+ tupdesc = CreateTemplateTupleDesc(2, false);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, "name",
+ TEXTOID, -1, 0, false);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 2, "setting",
+ TEXTOID, -1, 0, false);
+ }
+ else
+ {
+ const char *varname;
+
+ /* Get the canonical spelling of name */
+ (void) GetConfigOptionByName(name, &varname);
+
+ /* need a tuple descriptor representing a single TEXT column */
+ tupdesc = CreateTemplateTupleDesc(1, false);
+ TupleDescInitEntry(tupdesc, (AttrNumber) 1, (char *) varname,
+ TEXTOID, -1, 0, false);
+ }
+ return tupdesc;
}
/*
* SHOW command
*/
void
-ShowGUCConfigOption(const char *name)
+ShowGUCConfigOption(const char *name, DestReceiver *dest)
{
TupOutputState *tstate;
TupleDesc tupdesc;
- CommandDest dest = whereToSendOutput;
const char *varname;
char *value;
* SHOW ALL command
*/
void
-ShowAllGUCConfig(void)
+ShowAllGUCConfig(DestReceiver *dest)
{
int i;
TupOutputState *tstate;
TupleDesc tupdesc;
- CommandDest dest = whereToSendOutput;
char *values[2];
/* need a tuple descriptor representing two TEXT columns */
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.57 2003/05/05 00:44:56 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.58 2003/05/06 20:26:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
+#include "miscadmin.h"
#include "commands/portalcmds.h"
#include "executor/executor.h"
#include "utils/hsearch.h"
* ----------------
*/
-Portal CurrentPortal = NULL; /* globally visible pointer */
-
-
#define MAX_PORTALNAME_LEN NAMEDATALEN
typedef struct portalhashent
}
/*
+ * PortalCreateHoldStore
+ * Create the tuplestore for a portal.
+ */
+void
+PortalCreateHoldStore(Portal portal)
+{
+ MemoryContext oldcxt;
+
+ Assert(portal->holdContext == NULL);
+ Assert(portal->holdStore == NULL);
+
+ /*
+ * Create the memory context that is used for storage of the tuple set.
+ * Note this is NOT a child of the portal's heap memory.
+ */
+ portal->holdContext =
+ AllocSetContextCreate(PortalMemory,
+ "PortalHeapMemory",
+ ALLOCSET_DEFAULT_MINSIZE,
+ ALLOCSET_DEFAULT_INITSIZE,
+ ALLOCSET_DEFAULT_MAXSIZE);
+
+ /* Create the tuple store, selecting cross-transaction temp files. */
+ oldcxt = MemoryContextSwitchTo(portal->holdContext);
+
+ /* XXX: Should SortMem be used for this? */
+ portal->holdStore = tuplestore_begin_heap(true, true, SortMem);
+
+ MemoryContextSwitchTo(oldcxt);
+}
+
+/*
* PortalDrop
* Destroy the portal.
*
if (PointerIsValid(portal->cleanup))
(*portal->cleanup) (portal, isError);
+ /*
+ * Delete tuplestore if present. We should do this even under error
+ * conditions; since the tuplestore would have been using cross-
+ * transaction storage, its temp files need to be explicitly deleted.
+ */
+ if (portal->holdStore)
+ {
+ MemoryContext oldcontext;
+
+ oldcontext = MemoryContextSwitchTo(portal->holdContext);
+ tuplestore_end(portal->holdStore);
+ MemoryContextSwitchTo(oldcontext);
+ portal->holdStore = NULL;
+ }
+
/* delete tuplestore storage, if any */
if (portal->holdContext)
MemoryContextDelete(portal->holdContext);
* We are exiting the transaction that created a holdable
* cursor. Instead of dropping the portal, prepare it for
* access by later transactions.
- */
-
- /*
- * Create the memory context that is used for storage of
- * the held cursor's tuple set. Note this is NOT a child
- * of the portal's heap memory.
- */
- portal->holdContext =
- AllocSetContextCreate(PortalMemory,
- "PortalHeapMemory",
- ALLOCSET_DEFAULT_MINSIZE,
- ALLOCSET_DEFAULT_INITSIZE,
- ALLOCSET_DEFAULT_MAXSIZE);
-
- /*
- * Transfer data into the held tuplestore.
*
* Note that PersistHoldablePortal() must release all
* resources used by the portal that are local to the creating
* transaction.
*/
+ PortalCreateHoldStore(portal);
PersistHoldablePortal(portal);
}
else
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: printtup.h,v 1.25 2003/05/06 00:20:33 tgl Exp $
+ * $Id: printtup.h,v 1.26 2003/05/06 20:26:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "tcop/dest.h"
-extern DestReceiver *printtup_create_DR(bool isBinary, bool sendDescrip);
+extern DestReceiver *printtup_create_DR(CommandDest dest);
extern void SendRowDescriptionMessage(TupleDesc typeinfo, List *targetlist);
-extern void debugSetup(DestReceiver *self, int operation,
+extern void debugStartup(DestReceiver *self, int operation,
const char *portalName, TupleDesc typeinfo, List *targetlist);
extern void debugtup(HeapTuple tuple, TupleDesc typeinfo,
DestReceiver *self);
/* XXX these are really in executor/spi.c */
-extern void spi_dest_setup(DestReceiver *self, int operation,
+extern void spi_dest_startup(DestReceiver *self, int operation,
const char *portalName, TupleDesc typeinfo, List *targetlist);
-extern void spi_printtup(HeapTuple tuple, TupleDesc tupdesc,
+extern void spi_printtup(HeapTuple tuple, TupleDesc typeinfo,
DestReceiver *self);
#endif /* PRINTTUP_H */
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994-5, Regents of the University of California
*
- * $Id: explain.h,v 1.18 2003/02/02 23:46:38 tgl Exp $
+ * $Id: explain.h,v 1.19 2003/05/06 20:26:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "tcop/dest.h"
-extern void ExplainQuery(ExplainStmt *stmt, CommandDest dest);
+extern void ExplainQuery(ExplainStmt *stmt, DestReceiver *dest);
+
+extern TupleDesc ExplainResultDesc(ExplainStmt *stmt);
+
extern void ExplainOnePlan(QueryDesc *queryDesc, ExplainStmt *stmt,
TupOutputState *tstate);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: portalcmds.h,v 1.9 2003/05/05 00:44:56 tgl Exp $
+ * $Id: portalcmds.h,v 1.10 2003/05/06 20:26:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "utils/portal.h"
-extern void PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest);
+extern void PerformCursorOpen(DeclareCursorStmt *stmt);
-extern void PerformPortalFetch(FetchStmt *stmt, CommandDest dest,
+extern void PerformPortalFetch(FetchStmt *stmt, DestReceiver *dest,
char *completionTag);
extern void PerformPortalClose(const char *name);
*
* Copyright (c) 2002-2003, PostgreSQL Global Development Group
*
- * $Id: prepare.h,v 1.4 2003/05/05 00:44:56 tgl Exp $
+ * $Id: prepare.h,v 1.5 2003/05/06 20:26:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/* Utility statements PREPARE, EXECUTE, DEALLOCATE, EXPLAIN EXECUTE */
extern void PrepareQuery(PrepareStmt *stmt);
-extern void ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest);
+extern void ExecuteQuery(ExecuteStmt *stmt, DestReceiver *dest);
extern void DeallocateQuery(DeallocateStmt *stmt);
extern void ExplainExecuteQuery(ExplainStmt *stmt, TupOutputState *tstate);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: execdesc.h,v 1.22 2002/12/15 16:17:54 tgl Exp $
+ * $Id: execdesc.h,v 1.23 2003/05/06 20:26:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
CmdType operation; /* CMD_SELECT, CMD_UPDATE, etc. */
Query *parsetree; /* rewritten parsetree */
Plan *plantree; /* planner's output */
- CommandDest dest; /* the destination output of the execution */
+ DestReceiver *dest; /* the destination for tuple output */
const char *portalName; /* name of portal, or NULL */
ParamListInfo params; /* param values being passed in */
bool doInstrument; /* TRUE requests runtime instrumentation */
/* in pquery.c */
extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
- CommandDest dest, const char *portalName,
+ DestReceiver *dest, const char *portalName,
ParamListInfo params,
bool doInstrument);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: executor.h,v 1.93 2003/05/06 00:20:33 tgl Exp $
+ * $Id: executor.h,v 1.94 2003/05/06 20:26:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
TupleDesc tupType);
extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid);
+extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid);
extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg);
typedef struct TupOutputState
{
/* use "struct" here to allow forward reference */
struct AttInMetadata *metadata;
- DestReceiver *destfunc;
+ DestReceiver *dest;
} TupOutputState;
-extern TupOutputState *begin_tup_output_tupdesc(CommandDest dest, TupleDesc tupdesc);
+extern TupOutputState *begin_tup_output_tupdesc(DestReceiver *dest,
+ TupleDesc tupdesc);
extern void do_tup_output(TupOutputState *tstate, char **values);
extern void do_text_output_multiline(TupOutputState *tstate, char *text);
extern void end_tup_output(TupOutputState *tstate);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: tstoreReceiver.h,v 1.1 2003/03/27 16:55:11 momjian Exp $
+ * $Id: tstoreReceiver.h,v 1.2 2003/05/06 20:26:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#define TSTORE_RECEIVER_H
#include "tcop/dest.h"
+#include "utils/tuplestore.h"
-extern DestReceiver *tstoreReceiverCreateDR(void);
+
+extern DestReceiver *CreateTuplestoreDestReceiver(Tuplestorestate *tStore,
+ MemoryContext tContext);
#endif /* TSTORE_RECEIVER_H */
* dest.c defines three functions that implement destination management:
*
* BeginCommand: initialize the destination at start of command.
- * DestToFunction: return a pointer to a struct of destination-specific
+ * CreateDestReceiver: return a pointer to a struct of destination-specific
* receiver functions.
* 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).
+ * CreateDestReceiver returns a receiver object appropriate to the specified
+ * destination. The executor, as well as utility statements that can return
+ * tuples, are passed the resulting DestReceiver* pointer. Each executor run
+ * or utility execution calls the receiver's startup method, then the
+ * receiveTuple method (zero or more times), then the shutdown method.
+ * The same receiver object may be re-used multiple times; eventually it is
+ * destroyed by calling its destroy method.
*
- * The DestReceiver object returned by DestToFunction may be a statically
- * allocated object (for destination types that require no local state)
- * or can be a palloc'd object that has DestReceiver as its first field
- * and contains additional fields (see printtup.c for an example). These
- * additional fields are then accessible to the DestReceiver functions
- * by casting the DestReceiver* pointer passed to them.
- * The palloc'd object is pfree'd by the DestReceiver's cleanup function.
+ * The DestReceiver object returned by CreateDestReceiver may be a statically
+ * allocated object (for destination types that require no local state),
+ * in which case destroy is a no-op. Alternatively it can be a palloc'd
+ * object that has DestReceiver as its first field and contains additional
+ * fields (see printtup.c for an example). These additional fields are then
+ * accessible to the DestReceiver functions by casting the DestReceiver*
+ * pointer passed to them. The palloc'd object is pfree'd by the destroy
+ * method. Note that the caller of CreateDestReceiver should take care to
+ * do so in a memory context that is long-lived enough for the receiver
+ * object not to disappear while still needed.
+ *
+ * Special provision: None_Receiver is a permanently available receiver
+ * object for the None destination. This avoids useless creation/destroy
+ * calls in portal and cursor manipulations.
*
*
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: dest.h,v 1.36 2003/05/06 00:20:33 tgl Exp $
+ * $Id: dest.h,v 1.37 2003/05/06 20:26:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
* destination. Someday this will probably need to be improved.
*
* Note: only the values None, Debug, Remote are legal for the global
- * variable whereToSendOutput. The other values may be selected
+ * variable whereToSendOutput. The other values may be used
* as the destination for individual commands.
* ----------------
*/
* DestReceiver is a base type for destination-specific local state.
* In the simplest cases, there is no state info, just the function
* pointers that the executor must call.
+ *
+ * Note: the receiveTuple routine must be passed a TupleDesc identical to the
+ * one given to the startup routine. The reason for passing it again is just
+ * that some destinations would otherwise need dynamic state merely to
+ * remember the tupledesc pointer.
* ----------------
*/
typedef struct _DestReceiver DestReceiver;
/* Called for each tuple to be output: */
void (*receiveTuple) (HeapTuple tuple, TupleDesc typeinfo,
DestReceiver *self);
- /* Initialization and teardown: */
- void (*setup) (DestReceiver *self, int operation,
- const char *portalName,
- TupleDesc typeinfo,
- List *targetlist);
- void (*cleanup) (DestReceiver *self);
+ /* Per-executor-run initialization and shutdown: */
+ void (*startup) (DestReceiver *self, int operation,
+ const char *portalName,
+ TupleDesc typeinfo,
+ List *targetlist);
+ void (*shutdown) (DestReceiver *self);
+ /* Destroy the receiver object itself (if dynamically allocated) */
+ void (*destroy) (DestReceiver *self);
+ /* CommandDest code for this receiver */
+ CommandDest mydest;
/* Private fields might appear beyond this point... */
};
+extern DestReceiver *None_Receiver; /* permanent receiver for None */
+
/* The primary destination management functions */
extern void BeginCommand(const char *commandTag, CommandDest dest);
-extern DestReceiver *DestToFunction(CommandDest dest);
+extern DestReceiver *CreateDestReceiver(CommandDest dest);
extern void EndCommand(const char *commandTag, CommandDest dest);
/* Additional functions that go with destination management, more or less. */
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: pquery.h,v 1.25 2003/05/02 20:54:36 tgl Exp $
+ * $Id: pquery.h,v 1.26 2003/05/06 20:26:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
Plan *plan,
ParamListInfo params,
const char *portalName,
- CommandDest dest,
+ DestReceiver *dest,
char *completionTag);
+extern PortalStrategy ChoosePortalStrategy(List *parseTrees);
+
extern void PortalStart(Portal portal, ParamListInfo params);
extern bool PortalRun(Portal portal, long count,
- CommandDest dest, CommandDest altdest,
+ DestReceiver *dest, DestReceiver *altdest,
char *completionTag);
extern long PortalRunFetch(Portal portal,
FetchDirection fdirection,
long count,
- CommandDest dest);
+ DestReceiver *dest);
#endif /* PQUERY_H */
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: utility.h,v 1.17 2003/05/02 20:54:36 tgl Exp $
+ * $Id: utility.h,v 1.18 2003/05/06 20:26:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "executor/execdesc.h"
-extern void ProcessUtility(Node *parsetree, CommandDest dest,
+extern void ProcessUtility(Node *parsetree, DestReceiver *dest,
char *completionTag);
+extern bool UtilityReturnsTuples(Node *parsetree);
+
+extern TupleDesc UtilityTupleDescriptor(Node *parsetree);
+
extern const char *CreateCommandTag(Node *parsetree);
#endif /* UTILITY_H */
* Copyright 2000-2003 by PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>.
*
- * $Id: guc.h,v 1.30 2003/05/02 22:02:47 momjian Exp $
+ * $Id: guc.h,v 1.31 2003/05/06 20:26:28 tgl Exp $
*--------------------------------------------------------------------
*/
#ifndef GUC_H
#define GUC_H
#include "nodes/pg_list.h"
+#include "tcop/dest.h"
#include "utils/array.h"
extern bool set_config_option(const char *name, const char *value,
GucContext context, GucSource source,
bool isLocal, bool DoIt);
-extern void ShowGUCConfigOption(const char *name);
-extern void ShowAllGUCConfig(void);
+extern void ShowGUCConfigOption(const char *name, DestReceiver *dest);
+extern void ShowAllGUCConfig(DestReceiver *dest);
extern char *GetConfigOptionByName(const char *name, const char **varname);
extern char *GetConfigOptionByNum(int varnum, const char **varname, bool *noshow);
extern int GetNumConfigOptions(void);
extern void SetPGVariable(const char *name, List *args, bool is_local);
-extern void GetPGVariable(const char *name);
+extern void GetPGVariable(const char *name, DestReceiver *dest);
+extern TupleDesc GetPGVariableResultDesc(const char *name);
extern void ResetPGVariable(const char *name);
extern char *flatten_set_variable_args(const char *name, List *args);
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: portal.h,v 1.42 2003/05/02 20:54:36 tgl Exp $
+ * $Id: portal.h,v 1.43 2003/05/06 20:26:28 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#define PortalGetHeapMemory(portal) ((portal)->heap)
-/* Currently executing Portal, if any */
-extern DLLIMPORT Portal CurrentPortal;
-
-
/* Prototypes for functions in utils/mmgr/portalmem.c */
extern void EnablePortalManager(void);
extern void AtCommit_Portals(void);
List *parseTrees,
List *planTrees,
MemoryContext queryContext);
+extern void PortalCreateHoldStore(Portal portal);
#endif /* PORTAL_H */