Restructure command destination handling so that we pass around

DestReceiver pointers instead of just CommandDest values.  The DestReceiver
is made at the point where the destination is selected, rather than
deep inside the executor.  This cleans up the original kluge implementation
of tstoreReceiver.c, and makes it easy to support retrieving results
from utility statements inside portals.  Thus, you can now do fun things
like Bind and Execute a FETCH or EXPLAIN command, and it'll all work
as expected (e.g., you can Describe the portal, or use Execute's count
parameter to suspend the output partway through).  Implementation involves
stuffing the utility command's output into a Tuplestore, which would be
kind of annoying for huge output sets, but should be quite acceptable
for typical uses of utility commands.
This commit is contained in:
Tom Lane 2003-05-06 20:26:28 +00:00
parent 299fbb4b37
commit 79913910d4
28 changed files with 698 additions and 349 deletions

View File

@ -2,14 +2,14 @@
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -22,11 +22,13 @@
#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
@ -59,13 +61,41 @@ typedef struct
* ----------------
*/
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;
@ -77,8 +107,8 @@ printtup_create_DR(bool isBinary, bool 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;
@ -288,17 +318,28 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *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);
}
/* ----------------
@ -340,12 +381,12 @@ showatts(const char *name, TupleDesc tupleDesc)
}
/* ----------------
* 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

View File

@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -67,21 +67,15 @@ static Node *make_ors_ands_explicit(List *orclauses);
* 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)
{
@ -119,6 +113,22 @@ ExplainQuery(ExplainStmt *stmt, CommandDest dest)
end_tup_output(tstate);
}
/*
* 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
@ -169,7 +179,7 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
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);

View File

@ -14,7 +14,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -23,9 +23,9 @@
#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"
@ -37,7 +37,7 @@
* Execute SQL DECLARE CURSOR command.
*/
void
PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest)
PerformCursorOpen(DeclareCursorStmt *stmt)
{
List *rewritten;
Query *query;
@ -142,9 +142,10 @@ PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest)
*/
void
PerformPortalFetch(FetchStmt *stmt,
CommandDest dest,
DestReceiver *dest,
char *completionTag)
{
DestReceiver *mydest = dest;
Portal portal;
long nprocessed;
@ -168,7 +169,7 @@ PerformPortalFetch(FetchStmt *stmt,
}
/*
* 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
@ -176,21 +177,26 @@ PerformPortalFetch(FetchStmt *stmt,
* 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);
}
/*
@ -243,21 +249,6 @@ PortalCleanup(Portal portal, bool isError)
AssertArg(PortalIsValid(portal));
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
@ -284,7 +275,6 @@ void
PersistHoldablePortal(Portal portal)
{
QueryDesc *queryDesc = PortalGetQueryDesc(portal);
Portal saveCurrentPortal;
MemoryContext savePortalContext;
MemoryContext saveQueryContext;
MemoryContext oldcxt;
@ -294,26 +284,22 @@ PersistHoldablePortal(Portal portal)
* 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);
@ -326,10 +312,8 @@ PersistHoldablePortal(Portal portal)
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;
@ -344,12 +328,16 @@ PersistHoldablePortal(Portal portal)
*/
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.
*/
@ -359,7 +347,6 @@ PersistHoldablePortal(Portal portal)
/* Mark portal not active */
portal->portalActive = false;
CurrentPortal = saveCurrentPortal;
PortalContext = savePortalContext;
QueryContext = saveQueryContext;

View File

@ -10,7 +10,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -102,7 +102,7 @@ PrepareQuery(PrepareStmt *stmt)
* Implements the 'EXECUTE' utility statement.
*/
void
ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
ExecuteQuery(ExecuteStmt *stmt, DestReceiver *dest)
{
PreparedStatement *entry;
char *query_string;
@ -180,7 +180,7 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
*/
PortalStart(portal, paramLI);
(void) PortalRun(portal, FETCH_ALL, outputDest, outputDest, NULL);
(void) PortalRun(portal, FETCH_ALL, dest, dest, NULL);
PortalDrop(portal, false);
@ -488,19 +488,21 @@ ExplainExecuteQuery(ExplainStmt *stmt, TupOutputState *tstate)
{
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);
}

View File

@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -133,7 +133,7 @@ CreateSchemaCommand(CreateSchemaStmt *stmt)
/* 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();
}

View File

@ -26,7 +26,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -72,9 +72,9 @@ static TupleTableSlot *ExecutePlan(EState *estate, PlanState *planstate,
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);
@ -188,8 +188,7 @@ ExecutorRun(QueryDesc *queryDesc,
{
EState *estate;
CmdType operation;
CommandDest dest;
DestReceiver *destfunc;
DestReceiver *dest;
TupleTableSlot *result;
MemoryContext oldcontext;
@ -218,11 +217,10 @@ ExecutorRun(QueryDesc *queryDesc,
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
@ -235,12 +233,12 @@ ExecutorRun(QueryDesc *queryDesc,
operation,
count,
direction,
destfunc);
dest);
/*
* shutdown receiver
*/
(*destfunc->cleanup) (destfunc);
(*dest->shutdown) (dest);
MemoryContextSwitchTo(oldcontext);
@ -962,7 +960,7 @@ ExecutePlan(EState *estate,
CmdType operation,
long numberTuples,
ScanDirection direction,
DestReceiver *destfunc)
DestReceiver *dest)
{
JunkFilter *junkfilter;
TupleTableSlot *slot;
@ -1162,8 +1160,7 @@ lnext: ;
{
case CMD_SELECT:
ExecSelect(slot, /* slot containing tuple */
destfunc, /* destination's tuple-receiver
* obj */
dest, /* destination's tuple-receiver obj */
estate);
result = slot;
break;
@ -1237,7 +1234,7 @@ lnext: ;
*/
static void
ExecSelect(TupleTableSlot *slot,
DestReceiver *destfunc,
DestReceiver *dest,
EState *estate)
{
HeapTuple tuple;
@ -1251,6 +1248,8 @@ ExecSelect(TupleTableSlot *slot,
/*
* 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)
{
@ -1260,9 +1259,9 @@ ExecSelect(TupleTableSlot *slot,
}
/*
* 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)++;
}

View File

@ -15,7 +15,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -591,6 +591,49 @@ ExecTypeFromTL(List *targetList, bool hasoid)
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
*/
@ -713,17 +756,17 @@ BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
* 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;
}
@ -741,9 +784,9 @@ do_tup_output(TupOutputState *tstate, char **values)
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);
}
@ -766,7 +809,7 @@ do_text_output_multiline(TupOutputState *tstate, char *text)
if (eol)
*eol++ = '\0';
else
eol = text +strlen(text);
eol = text + strlen(text);
do_tup_output(tstate, &text);
text = eol;
@ -776,7 +819,8 @@ do_text_output_multiline(TupOutputState *tstate, char *text)
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);
}

View File

@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -245,7 +245,7 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
{
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. */

View File

@ -8,7 +8,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -38,7 +38,7 @@ static int _SPI_execute_plan(_SPI_plan *plan,
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);
@ -841,7 +841,8 @@ SPI_cursor_find(const char *name)
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 */
}
@ -853,7 +854,7 @@ SPI_cursor_fetch(Portal portal, bool forward, int count)
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);
}
@ -874,13 +875,13 @@ SPI_cursor_close(Portal portal)
/* =================== 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;
@ -891,12 +892,12 @@ spi_dest_setup(DestReceiver *self, int operation,
* _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 */
@ -1029,10 +1030,12 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan)
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))
@ -1051,14 +1054,13 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan)
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);
@ -1068,8 +1070,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan)
}
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)
@ -1144,20 +1145,21 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
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);
@ -1185,7 +1187,7 @@ _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount)
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:
@ -1216,13 +1218,13 @@ _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount)
_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;
@ -1253,7 +1255,7 @@ _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount)
*/
static void
_SPI_cursor_operation(Portal portal, bool forward, int count,
CommandDest dest)
DestReceiver *dest)
{
/* Check that the portal is valid */
if (!PortalIsValid(portal))
@ -1275,7 +1277,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
(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 */
@ -1343,7 +1345,7 @@ _SPI_checktuples(void)
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;

View File

@ -1,6 +1,6 @@
/*-------------------------------------------------------------------------
*
* tstore_receiver.c
* tstoreReceiver.c
* an implementation of DestReceiver that stores the result tuples in
* a Tuplestore
*
@ -9,7 +9,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -17,8 +17,7 @@
#include "postgres.h"
#include "executor/tstoreReceiver.h"
#include "utils/memutils.h"
#include "utils/portal.h"
typedef struct
{
@ -30,32 +29,13 @@ 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 */
}
/*
@ -73,28 +53,40 @@ tstoreReceiveTuple(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
}
/*
* 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;
}

View File

@ -8,14 +8,14 @@
* 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
@ -30,7 +30,6 @@
#include "access/printtup.h"
#include "access/xact.h"
#include "executor/tstoreReceiver.h"
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
@ -45,14 +44,15 @@ donothingReceive(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
}
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 */
}
/* ----------------
@ -60,17 +60,24 @@ donothingCleanup(DestReceiver *self)
* ----------------
*/
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
* ----------------
@ -82,26 +89,19 @@ BeginCommand(const char *commandTag, CommandDest dest)
}
/* ----------------
* 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;
@ -113,7 +113,12 @@ DestToFunction(CommandDest dest)
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 */

View File

@ -8,7 +8,7 @@
*
*
* 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
@ -656,6 +656,8 @@ pg_plan_queries(List *querytrees, bool needSnapshot)
static void
exec_simple_query(const char *query_string)
{
CommandDest dest = whereToSendOutput;
DestReceiver *receiver;
MemoryContext oldcontext;
List *parsetree_list,
*parsetree_item;
@ -682,6 +684,12 @@ exec_simple_query(const char *query_string)
if (save_log_statement_stats)
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
@ -745,7 +753,7 @@ exec_simple_query(const char *query_string)
set_ps_display(commandTag);
BeginCommand(commandTag, whereToSendOutput);
BeginCommand(commandTag, dest);
/*
* If we are in an aborted transaction, reject all commands except
@ -819,8 +827,8 @@ exec_simple_query(const char *query_string)
(void) PortalRun(portal,
FETCH_ALL,
whereToSendOutput,
whereToSendOutput,
receiver,
receiver,
completionTag);
PortalDrop(portal, false);
@ -868,14 +876,16 @@ exec_simple_query(const char *query_string)
* (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;
@ -1282,6 +1292,7 @@ static void
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;
@ -1363,15 +1374,19 @@ exec_execute_message(const char *portal_name, int is_binary, long max_rows)
/*
* 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)
@ -2344,7 +2359,7 @@ PostgresMain(int argc, char *argv[], const char *username)
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");
}
/*
@ -2412,7 +2427,6 @@ PostgresMain(int argc, char *argv[], const char *username)
*/
MemoryContextSwitchTo(TopMemoryContext);
MemoryContextResetAndDeleteChildren(ErrorContext);
CurrentPortal = NULL;
PortalContext = NULL;
QueryContext = NULL;

View File

@ -8,13 +8,14 @@
*
*
* 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"
@ -24,18 +25,18 @@
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);
@ -45,7 +46,7 @@ static void DoPortalRewind(Portal portal);
QueryDesc *
CreateQueryDesc(Query *parsetree,
Plan *plantree,
CommandDest dest,
DestReceiver *dest,
const char *portalName,
ParamListInfo params,
bool doInstrument)
@ -103,7 +104,7 @@ ProcessQuery(Query *parsetree,
Plan *plan,
ParamListInfo params,
const char *portalName,
CommandDest dest,
DestReceiver *dest,
char *completionTag)
{
int operation = parsetree->commandType;
@ -123,7 +124,7 @@ ProcessQuery(Query *parsetree,
* special-cases this case. (Perhaps would be cleaner to have
* an additional destination type?)
*/
dest = None;
dest = None_Receiver;
}
}
@ -185,6 +186,39 @@ ProcessQuery(Query *parsetree,
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
@ -202,7 +236,6 @@ void
PortalStart(Portal portal, ParamListInfo params)
{
MemoryContext oldContext;
Query *query = NULL;
QueryDesc *queryDesc;
AssertArg(PortalIsValid(portal));
@ -215,23 +248,9 @@ PortalStart(Portal portal, ParamListInfo params)
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
@ -247,9 +266,9 @@ PortalStart(Portal portal, ParamListInfo params)
* 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);
@ -261,6 +280,9 @@ PortalStart(Portal portal, ParamListInfo params)
* 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"
@ -272,10 +294,19 @@ PortalStart(Portal portal, ParamListInfo params)
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:
@ -310,11 +341,11 @@ PortalStart(Portal portal, ParamListInfo params)
* 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;
@ -336,10 +367,8 @@ PortalRun(Portal portal, long count, CommandDest dest, CommandDest altdest,
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;
@ -367,8 +396,14 @@ PortalRun(Portal portal, long count, CommandDest dest, CommandDest altdest,
*/
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;
}
/*
@ -404,7 +439,6 @@ PortalRun(Portal portal, long count, CommandDest dest, CommandDest altdest,
/* Mark portal not active */
portal->portalActive = false;
CurrentPortal = saveCurrentPortal;
PortalContext = savePortalContext;
QueryContext = saveQueryContext;
@ -431,7 +465,7 @@ long
PortalRunSelect(Portal portal,
bool forward,
long count,
CommandDest dest)
DestReceiver *dest)
{
QueryDesc *queryDesc;
ScanDirection direction;
@ -568,21 +602,18 @@ PortalRunSelect(Portal portal,
*/
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)
{
@ -608,7 +639,7 @@ RunFromStore(Portal portal, ScanDirection direction, long count,
if (tup == NULL)
break;
(*destfunc->receiveTuple) (tup, portal->tupDesc, destfunc);
(*dest->receiveTuple) (tup, portal->tupDesc, dest);
if (should_free)
pfree(tup);
@ -624,7 +655,7 @@ RunFromStore(Portal portal, ScanDirection direction, long count,
}
}
(*destfunc->cleanup) (destfunc);
(*dest->shutdown) (dest);
return (uint32) current_tuple_count;
}
@ -635,7 +666,7 @@ RunFromStore(Portal portal, ScanDirection direction, long count,
*/
static void
PortalRunUtility(Portal portal, Query *query,
CommandDest dest, char *completionTag)
DestReceiver *dest, char *completionTag)
{
Node *utilityStmt = query->utilityStmt;
@ -690,7 +721,7 @@ PortalRunUtility(Portal portal, Query *query,
*/
static void
PortalRunMulti(Portal portal,
CommandDest dest, CommandDest altdest,
DestReceiver *dest, DestReceiver *altdest,
char *completionTag)
{
List *plantree_list = portal->planTrees;
@ -807,10 +838,9 @@ long
PortalRunFetch(Portal portal,
FetchDirection fdirection,
long count,
CommandDest dest)
DestReceiver *dest)
{
long result;
Portal saveCurrentPortal;
MemoryContext savePortalContext;
MemoryContext saveQueryContext;
MemoryContext oldContext;
@ -828,10 +858,8 @@ PortalRunFetch(Portal portal,
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;
@ -856,7 +884,6 @@ PortalRunFetch(Portal portal,
/* Mark portal not active */
portal->portalActive = false;
CurrentPortal = saveCurrentPortal;
PortalContext = savePortalContext;
QueryContext = saveQueryContext;
@ -873,7 +900,7 @@ static long
DoPortalRunFetch(Portal portal,
FetchDirection fdirection,
long count,
CommandDest dest)
DestReceiver *dest)
{
bool forward;
@ -912,7 +939,8 @@ DoPortalRunFetch(Portal portal,
{
DoPortalRewind(portal);
if (count > 1)
PortalRunSelect(portal, true, count-1, None);
PortalRunSelect(portal, true, count-1,
None_Receiver);
}
else
{
@ -921,9 +949,11 @@ DoPortalRunFetch(Portal portal,
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);
}
@ -936,9 +966,9 @@ DoPortalRunFetch(Portal portal,
* (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 */
@ -955,7 +985,7 @@ DoPortalRunFetch(Portal portal,
* 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)
@ -965,7 +995,7 @@ DoPortalRunFetch(Portal portal,
* (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 */
@ -995,7 +1025,7 @@ DoPortalRunFetch(Portal portal,
/* 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;
@ -1011,7 +1041,7 @@ DoPortalRunFetch(Portal portal,
*/
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;
@ -1022,7 +1052,7 @@ DoPortalRunFetch(Portal portal,
/*
* 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;

View File

@ -10,7 +10,7 @@
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -47,6 +47,7 @@
#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"
@ -244,7 +245,7 @@ check_xact_readonly(Node *parsetree)
*/
void
ProcessUtility(Node *parsetree,
CommandDest dest,
DestReceiver *dest,
char *completionTag)
{
check_xact_readonly(parsetree);
@ -310,7 +311,7 @@ ProcessUtility(Node *parsetree,
* Portal (cursor) manipulation
*/
case T_DeclareCursorStmt:
PerformCursorOpen((DeclareCursorStmt *) parsetree, dest);
PerformCursorOpen((DeclareCursorStmt *) parsetree);
break;
case T_ClosePortalStmt:
@ -880,7 +881,7 @@ ProcessUtility(Node *parsetree,
{
VariableShowStmt *n = (VariableShowStmt *) parsetree;
GetPGVariable(n->name);
GetPGVariable(n->name, dest);
}
break;
@ -1028,6 +1029,137 @@ ProcessUtility(Node *parsetree,
}
}
/*
* 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

View File

@ -10,7 +10,7 @@
* 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 $
*
*--------------------------------------------------------------------
*/
@ -2438,12 +2438,41 @@ set_config_by_name(PG_FUNCTION_ARGS)
* 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;
}
/*
@ -2468,11 +2497,10 @@ ResetPGVariable(const char *name)
* 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;
@ -2497,12 +2525,11 @@ ShowGUCConfigOption(const char *name)
* 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 */

View File

@ -12,12 +12,13 @@
* 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"
@ -36,9 +37,6 @@
* ----------------
*/
Portal CurrentPortal = NULL; /* globally visible pointer */
#define MAX_PORTALNAME_LEN NAMEDATALEN
typedef struct portalhashent
@ -251,6 +249,38 @@ PortalDefineQuery(Portal portal,
portal->queryContext = queryContext;
}
/*
* 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.
@ -279,6 +309,21 @@ PortalDrop(Portal portal, bool isError)
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);
@ -360,27 +405,12 @@ AtCommit_Portals(void)
* 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

View File

@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -16,19 +16,19 @@
#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 */

View File

@ -6,7 +6,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -18,7 +18,10 @@
#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);

View File

@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -17,9 +17,9 @@
#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);

View File

@ -6,7 +6,7 @@
*
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -42,7 +42,7 @@ typedef struct
/* 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);

View File

@ -8,7 +8,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -33,7 +33,7 @@ typedef struct QueryDesc
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 */
@ -46,7 +46,7 @@ typedef struct QueryDesc
/* in pquery.c */
extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
CommandDest dest, const char *portalName,
DestReceiver *dest, const char *portalName,
ParamListInfo params,
bool doInstrument);

View File

@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -161,16 +161,18 @@ extern TupleTableSlot *ExecInitExtraTupleSlot(EState *estate);
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);

View File

@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -16,7 +16,10 @@
#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 */

View File

@ -21,30 +21,40 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -63,7 +73,7 @@
* 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.
* ----------------
*/
@ -84,6 +94,11 @@ typedef enum
* 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;
@ -93,19 +108,25 @@ struct _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. */

View File

@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -21,18 +21,20 @@ extern void ProcessQuery(Query *parsetree,
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 */

View File

@ -7,7 +7,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -16,9 +16,13 @@
#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 */

View File

@ -7,13 +7,14 @@
* 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"
@ -119,14 +120,15 @@ extern void ParseLongOption(const char *string, char **name, char **value);
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);

View File

@ -39,7 +39,7 @@
* 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 $
*
*-------------------------------------------------------------------------
*/
@ -156,10 +156,6 @@ typedef struct PortalData
#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);
@ -176,5 +172,6 @@ extern void PortalDefineQuery(Portal portal,
List *parseTrees,
List *planTrees,
MemoryContext queryContext);
extern void PortalCreateHoldStore(Portal portal);
#endif /* PORTAL_H */