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 * printtup.c
* Routines to print out tuples to the destination (both frontend * 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) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/access/common/printtup.c,v 1.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" #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); const char *portalName, TupleDesc typeinfo, List *targetlist);
static void printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self); static void printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self);
static void printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self); static void printtup_internal(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self);
static void printtup_cleanup(DestReceiver *self); static void printtup_shutdown(DestReceiver *self);
static void printtup_destroy(DestReceiver *self);
/* ---------------------------------------------------------------- /* ----------------------------------------------------------------
* printtup / debugtup support * printtup / debugtup support
@ -59,13 +61,41 @@ typedef struct
* ---------------- * ----------------
*/ */
DestReceiver * DestReceiver *
printtup_create_DR(bool isBinary, bool sendDescrip) printtup_create_DR(CommandDest dest)
{ {
DR_printtup *self = (DR_printtup *) palloc(sizeof(DR_printtup)); 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.receiveTuple = isBinary ? printtup_internal : printtup;
self->pub.setup = printtup_setup; self->pub.startup = printtup_startup;
self->pub.cleanup = printtup_cleanup; self->pub.shutdown = printtup_shutdown;
self->pub.destroy = printtup_destroy;
self->pub.mydest = dest;
self->sendDescrip = sendDescrip; self->sendDescrip = sendDescrip;
@ -77,8 +107,8 @@ printtup_create_DR(bool isBinary, bool sendDescrip)
} }
static void static void
printtup_setup(DestReceiver *self, int operation, printtup_startup(DestReceiver *self, int operation,
const char *portalName, TupleDesc typeinfo, List *targetlist) const char *portalName, TupleDesc typeinfo, List *targetlist)
{ {
DR_printtup *myState = (DR_printtup *) self; DR_printtup *myState = (DR_printtup *) self;
@ -288,17 +318,28 @@ printtup(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
} }
/* ---------------- /* ----------------
* printtup_cleanup * printtup_shutdown
* ---------------- * ----------------
*/ */
static void static void
printtup_cleanup(DestReceiver *self) printtup_shutdown(DestReceiver *self)
{ {
DR_printtup *myState = (DR_printtup *) self; DR_printtup *myState = (DR_printtup *) self;
if (myState->myinfo) if (myState->myinfo)
pfree(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 void
debugSetup(DestReceiver *self, int operation, debugStartup(DestReceiver *self, int operation,
const char *portalName, TupleDesc typeinfo, List *targetlist) const char *portalName, TupleDesc typeinfo, List *targetlist)
{ {
/* /*
* show the return type of the tuples * show the return type of the tuples

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California * Portions Copyright (c) 1994-5, Regents of the University of California
* *
* IDENTIFICATION * 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 * execute an EXPLAIN command
*/ */
void void
ExplainQuery(ExplainStmt *stmt, CommandDest dest) ExplainQuery(ExplainStmt *stmt, DestReceiver *dest)
{ {
Query *query = stmt->query; Query *query = stmt->query;
TupOutputState *tstate; TupOutputState *tstate;
TupleDesc tupdesc;
List *rewritten; List *rewritten;
List *l; 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 */ /* 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) if (query->commandType == CMD_UTILITY)
{ {
@ -119,6 +113,22 @@ ExplainQuery(ExplainStmt *stmt, CommandDest dest)
end_tup_output(tstate); 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 - * ExplainOneQuery -
* print out the execution plan for one query * print out the execution plan for one query
@ -169,7 +179,7 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
plan = planner(query, isCursor, cursorOptions); plan = planner(query, isCursor, cursorOptions);
/* Create a QueryDesc requesting no output */ /* Create a QueryDesc requesting no output */
queryDesc = CreateQueryDesc(query, plan, None, NULL, NULL, queryDesc = CreateQueryDesc(query, plan, None_Receiver, NULL, NULL,
stmt->analyze); stmt->analyze);
ExplainOnePlan(queryDesc, stmt, tstate); ExplainOnePlan(queryDesc, stmt, tstate);

View File

@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * 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 <limits.h>
#include "miscadmin.h"
#include "commands/portalcmds.h" #include "commands/portalcmds.h"
#include "executor/executor.h" #include "executor/executor.h"
#include "executor/tstoreReceiver.h"
#include "optimizer/planner.h" #include "optimizer/planner.h"
#include "rewrite/rewriteHandler.h" #include "rewrite/rewriteHandler.h"
#include "tcop/pquery.h" #include "tcop/pquery.h"
@ -37,7 +37,7 @@
* Execute SQL DECLARE CURSOR command. * Execute SQL DECLARE CURSOR command.
*/ */
void void
PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest) PerformCursorOpen(DeclareCursorStmt *stmt)
{ {
List *rewritten; List *rewritten;
Query *query; Query *query;
@ -142,9 +142,10 @@ PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest)
*/ */
void void
PerformPortalFetch(FetchStmt *stmt, PerformPortalFetch(FetchStmt *stmt,
CommandDest dest, DestReceiver *dest,
char *completionTag) char *completionTag)
{ {
DestReceiver *mydest = dest;
Portal portal; Portal portal;
long nprocessed; 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 * If fetching from a binary cursor and the requested destination is
* Remote, change it to RemoteInternal. Note we do NOT change if the * 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. * specification wins out over the cursor's type.
*/ */
if (stmt->ismove) if (stmt->ismove)
dest = None; mydest = CreateDestReceiver(None);
else if (dest == Remote && (portal->cursorOptions & CURSOR_OPT_BINARY)) else if (dest->mydest == Remote &&
dest = RemoteInternal; (portal->cursorOptions & CURSOR_OPT_BINARY))
mydest = CreateDestReceiver(RemoteInternal);
/* Do it */ /* Do it */
nprocessed = PortalRunFetch(portal, nprocessed = PortalRunFetch(portal,
stmt->direction, stmt->direction,
stmt->howMany, stmt->howMany,
dest); mydest);
/* Return command status if wanted */ /* Return command status if wanted */
if (completionTag) if (completionTag)
snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %ld", snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %ld",
stmt->ismove ? "MOVE" : "FETCH", stmt->ismove ? "MOVE" : "FETCH",
nprocessed); 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(PortalIsValid(portal));
AssertArg(portal->cleanup == PortalCleanup); 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 * Shut down executor, if still running. We skip this during error
* abort, since other mechanisms will take care of releasing executor * abort, since other mechanisms will take care of releasing executor
@ -284,7 +275,6 @@ void
PersistHoldablePortal(Portal portal) PersistHoldablePortal(Portal portal)
{ {
QueryDesc *queryDesc = PortalGetQueryDesc(portal); QueryDesc *queryDesc = PortalGetQueryDesc(portal);
Portal saveCurrentPortal;
MemoryContext savePortalContext; MemoryContext savePortalContext;
MemoryContext saveQueryContext; MemoryContext saveQueryContext;
MemoryContext oldcxt; MemoryContext oldcxt;
@ -294,26 +284,22 @@ PersistHoldablePortal(Portal portal)
* inside the transaction that originally created it. * inside the transaction that originally created it.
*/ */
Assert(portal->createXact == GetCurrentTransactionId()); Assert(portal->createXact == GetCurrentTransactionId());
Assert(portal->holdStore == NULL);
Assert(queryDesc != NULL); Assert(queryDesc != NULL);
Assert(portal->portalReady); Assert(portal->portalReady);
Assert(!portal->portalDone); Assert(!portal->portalDone);
/* /*
* This context is used to store the tuple set. * Caller must have created the tuplestore already.
* Caller must have created it already.
*/ */
Assert(portal->holdContext != NULL); Assert(portal->holdContext != NULL);
oldcxt = MemoryContextSwitchTo(portal->holdContext); Assert(portal->holdStore != NULL);
/* XXX: Should SortMem be used for this? */
portal->holdStore = tuplestore_begin_heap(true, true, SortMem);
/* /*
* Before closing down the executor, we must copy the tupdesc, since * Before closing down the executor, we must copy the tupdesc into
* it was created in executor memory. Note we are copying it into * long-term memory, since it was created in executor memory.
* the holdContext.
*/ */
oldcxt = MemoryContextSwitchTo(portal->holdContext);
portal->tupDesc = CreateTupleDescCopy(portal->tupDesc); portal->tupDesc = CreateTupleDescCopy(portal->tupDesc);
MemoryContextSwitchTo(oldcxt); MemoryContextSwitchTo(oldcxt);
@ -326,10 +312,8 @@ PersistHoldablePortal(Portal portal)
portal->portalActive = true; portal->portalActive = true;
/* /*
* Set global portal and context pointers. * Set global portal context pointers.
*/ */
saveCurrentPortal = CurrentPortal;
CurrentPortal = portal;
savePortalContext = PortalContext; savePortalContext = PortalContext;
PortalContext = PortalGetHeapMemory(portal); PortalContext = PortalGetHeapMemory(portal);
saveQueryContext = QueryContext; saveQueryContext = QueryContext;
@ -344,12 +328,16 @@ PersistHoldablePortal(Portal portal)
*/ */
ExecutorRewind(queryDesc); ExecutorRewind(queryDesc);
/* Set the destination to output to the tuplestore */ /* Change the destination to output to the tuplestore */
queryDesc->dest = Tuplestore; queryDesc->dest = CreateTuplestoreDestReceiver(portal->holdStore,
portal->holdContext);
/* Fetch the result set into the tuplestore */ /* Fetch the result set into the tuplestore */
ExecutorRun(queryDesc, ForwardScanDirection, 0L); ExecutorRun(queryDesc, ForwardScanDirection, 0L);
(*queryDesc->dest->destroy) (queryDesc->dest);
queryDesc->dest = NULL;
/* /*
* Now shut down the inner executor. * Now shut down the inner executor.
*/ */
@ -359,7 +347,6 @@ PersistHoldablePortal(Portal portal)
/* Mark portal not active */ /* Mark portal not active */
portal->portalActive = false; portal->portalActive = false;
CurrentPortal = saveCurrentPortal;
PortalContext = savePortalContext; PortalContext = savePortalContext;
QueryContext = saveQueryContext; QueryContext = saveQueryContext;

View File

@ -10,7 +10,7 @@
* Copyright (c) 2002-2003, PostgreSQL Global Development Group * Copyright (c) 2002-2003, PostgreSQL Global Development Group
* *
* IDENTIFICATION * 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. * Implements the 'EXECUTE' utility statement.
*/ */
void void
ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest) ExecuteQuery(ExecuteStmt *stmt, DestReceiver *dest)
{ {
PreparedStatement *entry; PreparedStatement *entry;
char *query_string; char *query_string;
@ -180,7 +180,7 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest)
*/ */
PortalStart(portal, paramLI); PortalStart(portal, paramLI);
(void) PortalRun(portal, FETCH_ALL, outputDest, outputDest, NULL); (void) PortalRun(portal, FETCH_ALL, dest, dest, NULL);
PortalDrop(portal, false); PortalDrop(portal, false);
@ -488,19 +488,21 @@ ExplainExecuteQuery(ExplainStmt *stmt, TupOutputState *tstate)
{ {
QueryDesc *qdesc; QueryDesc *qdesc;
/* Create a QueryDesc requesting no output */
qdesc = CreateQueryDesc(query, plan, None, NULL,
paramLI, stmt->analyze);
if (execstmt->into) if (execstmt->into)
{ {
if (qdesc->operation != CMD_SELECT) if (query->commandType != CMD_SELECT)
elog(ERROR, "INTO clause specified for non-SELECT query"); elog(ERROR, "INTO clause specified for non-SELECT query");
/* Copy the query so we can modify it */
query = copyObject(query);
query->into = execstmt->into; 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); ExplainOnePlan(qdesc, stmt, tstate);
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 */ /* schemas should contain only utility stmts */
Assert(querytree->commandType == CMD_UTILITY); Assert(querytree->commandType == CMD_UTILITY);
/* do this step */ /* do this step */
ProcessUtility(querytree->utilityStmt, None, NULL); ProcessUtility(querytree->utilityStmt, None_Receiver, NULL);
/* make sure later steps can see the object created here */ /* make sure later steps can see the object created here */
CommandCounterIncrement(); CommandCounterIncrement();
} }

View File

@ -26,7 +26,7 @@
* *
* *
* IDENTIFICATION * 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, CmdType operation,
long numberTuples, long numberTuples,
ScanDirection direction, ScanDirection direction,
DestReceiver *destfunc); DestReceiver *dest);
static void ExecSelect(TupleTableSlot *slot, static void ExecSelect(TupleTableSlot *slot,
DestReceiver *destfunc, DestReceiver *dest,
EState *estate); EState *estate);
static void ExecInsert(TupleTableSlot *slot, ItemPointer tupleid, static void ExecInsert(TupleTableSlot *slot, ItemPointer tupleid,
EState *estate); EState *estate);
@ -188,8 +188,7 @@ ExecutorRun(QueryDesc *queryDesc,
{ {
EState *estate; EState *estate;
CmdType operation; CmdType operation;
CommandDest dest; DestReceiver *dest;
DestReceiver *destfunc;
TupleTableSlot *result; TupleTableSlot *result;
MemoryContext oldcontext; MemoryContext oldcontext;
@ -218,11 +217,10 @@ ExecutorRun(QueryDesc *queryDesc,
estate->es_processed = 0; estate->es_processed = 0;
estate->es_lastoid = InvalidOid; estate->es_lastoid = InvalidOid;
destfunc = DestToFunction(dest); (*dest->startup) (dest, operation,
(*destfunc->setup) (destfunc, operation, queryDesc->portalName,
queryDesc->portalName, queryDesc->tupDesc,
queryDesc->tupDesc, queryDesc->planstate->plan->targetlist);
queryDesc->planstate->plan->targetlist);
/* /*
* run plan * run plan
@ -235,12 +233,12 @@ ExecutorRun(QueryDesc *queryDesc,
operation, operation,
count, count,
direction, direction,
destfunc); dest);
/* /*
* shutdown receiver * shutdown receiver
*/ */
(*destfunc->cleanup) (destfunc); (*dest->shutdown) (dest);
MemoryContextSwitchTo(oldcontext); MemoryContextSwitchTo(oldcontext);
@ -962,7 +960,7 @@ ExecutePlan(EState *estate,
CmdType operation, CmdType operation,
long numberTuples, long numberTuples,
ScanDirection direction, ScanDirection direction,
DestReceiver *destfunc) DestReceiver *dest)
{ {
JunkFilter *junkfilter; JunkFilter *junkfilter;
TupleTableSlot *slot; TupleTableSlot *slot;
@ -1162,8 +1160,7 @@ lnext: ;
{ {
case CMD_SELECT: case CMD_SELECT:
ExecSelect(slot, /* slot containing tuple */ ExecSelect(slot, /* slot containing tuple */
destfunc, /* destination's tuple-receiver dest, /* destination's tuple-receiver obj */
* obj */
estate); estate);
result = slot; result = slot;
break; break;
@ -1237,7 +1234,7 @@ lnext: ;
*/ */
static void static void
ExecSelect(TupleTableSlot *slot, ExecSelect(TupleTableSlot *slot,
DestReceiver *destfunc, DestReceiver *dest,
EState *estate) EState *estate)
{ {
HeapTuple tuple; HeapTuple tuple;
@ -1251,6 +1248,8 @@ ExecSelect(TupleTableSlot *slot,
/* /*
* insert the tuple into the "into relation" * 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) 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(); IncrRetrieved();
(estate->es_processed)++; (estate->es_processed)++;
} }

View File

@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * 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; 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 * 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 * Table Function capability. Currently used by EXPLAIN and SHOW ALL
*/ */
TupOutputState * TupOutputState *
begin_tup_output_tupdesc(CommandDest dest, TupleDesc tupdesc) begin_tup_output_tupdesc(DestReceiver *dest, TupleDesc tupdesc)
{ {
TupOutputState *tstate; TupOutputState *tstate;
tstate = (TupOutputState *) palloc(sizeof(TupOutputState)); tstate = (TupOutputState *) palloc(sizeof(TupOutputState));
tstate->metadata = TupleDescGetAttInMetadata(tupdesc); tstate->metadata = TupleDescGetAttInMetadata(tupdesc);
tstate->destfunc = DestToFunction(dest); tstate->dest = dest;
(*tstate->destfunc->setup) (tstate->destfunc, (int) CMD_SELECT, (*tstate->dest->startup) (tstate->dest, (int) CMD_SELECT,
NULL, tupdesc, NIL); NULL, tupdesc, NIL);
return tstate; return tstate;
} }
@ -741,9 +784,9 @@ do_tup_output(TupOutputState *tstate, char **values)
HeapTuple tuple = BuildTupleFromCStrings(tstate->metadata, values); HeapTuple tuple = BuildTupleFromCStrings(tstate->metadata, values);
/* send the tuple to the receiver */ /* send the tuple to the receiver */
(*tstate->destfunc->receiveTuple) (tuple, (*tstate->dest->receiveTuple) (tuple,
tstate->metadata->tupdesc, tstate->metadata->tupdesc,
tstate->destfunc); tstate->dest);
/* clean up */ /* clean up */
heap_freetuple(tuple); heap_freetuple(tuple);
} }
@ -766,7 +809,7 @@ do_text_output_multiline(TupOutputState *tstate, char *text)
if (eol) if (eol)
*eol++ = '\0'; *eol++ = '\0';
else else
eol = text +strlen(text); eol = text + strlen(text);
do_tup_output(tstate, &text); do_tup_output(tstate, &text);
text = eol; text = eol;
@ -776,7 +819,8 @@ do_text_output_multiline(TupOutputState *tstate, char *text)
void void
end_tup_output(TupOutputState *tstate) 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? */ /* XXX worth cleaning up the attinmetadata? */
pfree(tstate); pfree(tstate);
} }

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); Assert(es->qd == NULL);
es->qd = CreateQueryDesc(es->query, es->plan, es->qd = CreateQueryDesc(es->query, es->plan,
None, NULL, None_Receiver, NULL,
fcache->paramLI, false); fcache->paramLI, false);
/* Utility commands don't need Executor. */ /* Utility commands don't need Executor. */

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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); Datum *Values, const char *Nulls, int tcount);
static void _SPI_cursor_operation(Portal portal, bool forward, int count, 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); static _SPI_plan *_SPI_copy_plan(_SPI_plan *plan, int location);
@ -841,7 +841,8 @@ SPI_cursor_find(const char *name)
void void
SPI_cursor_fetch(Portal portal, bool forward, int count) 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 void
SPI_cursor_move(Portal portal, bool forward, int count) 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 =================== */ /* =================== private functions =================== */
/* /*
* spi_dest_setup * spi_dest_startup
* Initialize to receive tuples from Executor into SPITupleTable * Initialize to receive tuples from Executor into SPITupleTable
* of current SPI procedure * of current SPI procedure
*/ */
void void
spi_dest_setup(DestReceiver *self, int operation, spi_dest_startup(DestReceiver *self, int operation,
const char *portalName, TupleDesc typeinfo, List *targetlist) const char *portalName, TupleDesc typeinfo, List *targetlist)
{ {
SPITupleTable *tuptable; SPITupleTable *tuptable;
MemoryContext oldcxt; MemoryContext oldcxt;
@ -891,12 +892,12 @@ spi_dest_setup(DestReceiver *self, int operation,
* _SPI_connected * _SPI_connected
*/ */
if (_SPI_curid != _SPI_connected || _SPI_connected < 0) 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])) 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) 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 */ 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); Query *queryTree = (Query *) lfirst(query_list_item);
Plan *planTree; Plan *planTree;
QueryDesc *qdesc; QueryDesc *qdesc;
DestReceiver *dest;
planTree = pg_plan_query(queryTree); planTree = pg_plan_query(queryTree);
plan_list = lappend(plan_list, planTree); plan_list = lappend(plan_list, planTree);
dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None);
if (queryTree->commandType == CMD_UTILITY) if (queryTree->commandType == CMD_UTILITY)
{ {
if (IsA(queryTree->utilityStmt, CopyStmt)) if (IsA(queryTree->utilityStmt, CopyStmt))
@ -1051,14 +1054,13 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan)
res = SPI_OK_UTILITY; res = SPI_OK_UTILITY;
if (plan == NULL) if (plan == NULL)
{ {
ProcessUtility(queryTree->utilityStmt, None, NULL); ProcessUtility(queryTree->utilityStmt, dest, NULL);
CommandCounterIncrement(); CommandCounterIncrement();
} }
} }
else if (plan == NULL) else if (plan == NULL)
{ {
qdesc = CreateQueryDesc(queryTree, planTree, qdesc = CreateQueryDesc(queryTree, planTree, dest,
queryTree->canSetTag ? SPI : None,
NULL, NULL, false); NULL, NULL, false);
res = _SPI_pquery(qdesc, true, res = _SPI_pquery(qdesc, true,
queryTree->canSetTag ? tcount : 0); queryTree->canSetTag ? tcount : 0);
@ -1068,8 +1070,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan)
} }
else else
{ {
qdesc = CreateQueryDesc(queryTree, planTree, qdesc = CreateQueryDesc(queryTree, planTree, dest,
queryTree->canSetTag ? SPI : None,
NULL, NULL, false); NULL, NULL, false);
res = _SPI_pquery(qdesc, false, 0); res = _SPI_pquery(qdesc, false, 0);
if (res < 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); Query *queryTree = (Query *) lfirst(query_list_item);
Plan *planTree; Plan *planTree;
QueryDesc *qdesc; QueryDesc *qdesc;
DestReceiver *dest;
planTree = lfirst(plan_list); planTree = lfirst(plan_list);
plan_list = lnext(plan_list); plan_list = lnext(plan_list);
dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None);
if (queryTree->commandType == CMD_UTILITY) if (queryTree->commandType == CMD_UTILITY)
{ {
ProcessUtility(queryTree->utilityStmt, None, NULL); ProcessUtility(queryTree->utilityStmt, dest, NULL);
res = SPI_OK_UTILITY; res = SPI_OK_UTILITY;
CommandCounterIncrement(); CommandCounterIncrement();
} }
else else
{ {
qdesc = CreateQueryDesc(queryTree, planTree, qdesc = CreateQueryDesc(queryTree, planTree, dest,
queryTree->canSetTag ? SPI : None,
NULL, paramLI, false); NULL, paramLI, false);
res = _SPI_pquery(qdesc, true, res = _SPI_pquery(qdesc, true,
queryTree->canSetTag ? tcount : 0); queryTree->canSetTag ? tcount : 0);
@ -1185,7 +1187,7 @@ _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount)
if (queryDesc->parsetree->into != NULL) /* select into table */ if (queryDesc->parsetree->into != NULL) /* select into table */
{ {
res = SPI_OK_SELINTO; res = SPI_OK_SELINTO;
queryDesc->dest = None; /* don't output results anywhere */ queryDesc->dest = None_Receiver; /* don't output results */
} }
break; break;
case CMD_INSERT: case CMD_INSERT:
@ -1216,13 +1218,13 @@ _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount)
_SPI_current->processed = queryDesc->estate->es_processed; _SPI_current->processed = queryDesc->estate->es_processed;
save_lastoid = queryDesc->estate->es_lastoid; save_lastoid = queryDesc->estate->es_lastoid;
if (operation == CMD_SELECT && queryDesc->dest == SPI) if (operation == CMD_SELECT && queryDesc->dest->mydest == SPI)
{ {
if (_SPI_checktuples()) if (_SPI_checktuples())
elog(FATAL, "SPI_select: # of processed tuples check failed"); elog(FATAL, "SPI_select: # of processed tuples check failed");
} }
if (queryDesc->dest == SPI) if (queryDesc->dest->mydest == SPI)
{ {
SPI_processed = _SPI_current->processed; SPI_processed = _SPI_current->processed;
SPI_lastoid = save_lastoid; SPI_lastoid = save_lastoid;
@ -1253,7 +1255,7 @@ _SPI_pquery(QueryDesc *queryDesc, bool runit, int tcount)
*/ */
static void static void
_SPI_cursor_operation(Portal portal, bool forward, int count, _SPI_cursor_operation(Portal portal, bool forward, int count,
CommandDest dest) DestReceiver *dest)
{ {
/* Check that the portal is valid */ /* Check that the portal is valid */
if (!PortalIsValid(portal)) if (!PortalIsValid(portal))
@ -1275,7 +1277,7 @@ _SPI_cursor_operation(Portal portal, bool forward, int count,
(long) count, (long) count,
dest); dest);
if (dest == SPI && _SPI_checktuples()) if (dest->mydest == SPI && _SPI_checktuples())
elog(FATAL, "SPI_fetch: # of processed tuples check failed"); elog(FATAL, "SPI_fetch: # of processed tuples check failed");
/* Put the result into place for access by caller */ /* Put the result into place for access by caller */
@ -1343,7 +1345,7 @@ _SPI_checktuples(void)
SPITupleTable *tuptable = _SPI_current->tuptable; SPITupleTable *tuptable = _SPI_current->tuptable;
bool failed = false; bool failed = false;
if (tuptable == NULL) /* spi_dest_setup was not called */ if (tuptable == NULL) /* spi_dest_startup was not called */
failed = true; failed = true;
else if (processed != (tuptable->alloced - tuptable->free)) else if (processed != (tuptable->alloced - tuptable->free))
failed = true; failed = true;

View File

@ -1,6 +1,6 @@
/*------------------------------------------------------------------------- /*-------------------------------------------------------------------------
* *
* tstore_receiver.c * tstoreReceiver.c
* an implementation of DestReceiver that stores the result tuples in * an implementation of DestReceiver that stores the result tuples in
* a Tuplestore * a Tuplestore
* *
@ -9,7 +9,7 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/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 "postgres.h"
#include "executor/tstoreReceiver.h" #include "executor/tstoreReceiver.h"
#include "utils/memutils.h"
#include "utils/portal.h"
typedef struct typedef struct
{ {
@ -30,32 +29,13 @@ typedef struct
/* /*
* Prepare to receive tuples from executor. * 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 static void
tstoreSetupReceiver(DestReceiver *self, int operation, tstoreStartupReceiver(DestReceiver *self, int operation,
const char *portalname, const char *portalname,
TupleDesc typeinfo, List *targetlist) TupleDesc typeinfo, List *targetlist)
{ {
TStoreState *myState = (TStoreState *) self; /* do nothing */
/* 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;
} }
/* /*
@ -73,28 +53,40 @@ tstoreReceiveTuple(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
} }
/* /*
* Clean up * Clean up at end of an executor run
*/ */
static void static void
tstoreCleanupReceiver(DestReceiver *self) tstoreShutdownReceiver(DestReceiver *self)
{ {
/* do nothing */ /* do nothing */
} }
/*
* Destroy receiver when done with it
*/
static void
tstoreDestroyReceiver(DestReceiver *self)
{
pfree(self);
}
/* /*
* Initially create a DestReceiver object. * Initially create a DestReceiver object.
*/ */
DestReceiver * DestReceiver *
tstoreReceiverCreateDR(void) CreateTuplestoreDestReceiver(Tuplestorestate *tStore,
MemoryContext tContext)
{ {
TStoreState *self = (TStoreState *) palloc(sizeof(TStoreState)); TStoreState *self = (TStoreState *) palloc(sizeof(TStoreState));
self->pub.receiveTuple = tstoreReceiveTuple; self->pub.receiveTuple = tstoreReceiveTuple;
self->pub.setup = tstoreSetupReceiver; self->pub.startup = tstoreStartupReceiver;
self->pub.cleanup = tstoreCleanupReceiver; self->pub.shutdown = tstoreShutdownReceiver;
self->pub.destroy = tstoreDestroyReceiver;
self->pub.mydest = Tuplestore;
self->tstore = NULL; self->tstore = tStore;
self->cxt = NULL; self->cxt = tContext;
return (DestReceiver *) self; return (DestReceiver *) self;
} }

View File

@ -8,14 +8,14 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.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 * INTERFACE ROUTINES
* BeginCommand - initialize the destination at start of command * 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 * EndCommand - clean up the destination at end of command
* NullCommand - tell dest that an empty query string was recognized * NullCommand - tell dest that an empty query string was recognized
* ReadyForQuery - tell dest that we are ready for a new query * ReadyForQuery - tell dest that we are ready for a new query
@ -30,7 +30,6 @@
#include "access/printtup.h" #include "access/printtup.h"
#include "access/xact.h" #include "access/xact.h"
#include "executor/tstoreReceiver.h"
#include "libpq/libpq.h" #include "libpq/libpq.h"
#include "libpq/pqformat.h" #include "libpq/pqformat.h"
@ -45,14 +44,15 @@ donothingReceive(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
} }
static void static void
donothingSetup(DestReceiver *self, int operation, donothingStartup(DestReceiver *self, int operation,
const char *portalName, TupleDesc typeinfo, List *targetlist) const char *portalName, TupleDesc typeinfo, List *targetlist)
{ {
} }
static void static void
donothingCleanup(DestReceiver *self) donothingCleanup(DestReceiver *self)
{ {
/* this is used for both shutdown and destroy methods */
} }
/* ---------------- /* ----------------
@ -60,17 +60,24 @@ donothingCleanup(DestReceiver *self)
* ---------------- * ----------------
*/ */
static DestReceiver donothingDR = { static DestReceiver donothingDR = {
donothingReceive, donothingSetup, donothingCleanup donothingReceive, donothingStartup, donothingCleanup, donothingCleanup,
None
}; };
static DestReceiver debugtupDR = { static DestReceiver debugtupDR = {
debugtup, debugSetup, donothingCleanup debugtup, debugStartup, donothingCleanup, donothingCleanup,
Debug
}; };
static DestReceiver spi_printtupDR = { 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 * 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 * DestReceiver *
DestToFunction(CommandDest dest) CreateDestReceiver(CommandDest dest)
{ {
switch (dest) switch (dest)
{ {
case Remote: case Remote:
return printtup_create_DR(false, true);
case RemoteInternal: case RemoteInternal:
return printtup_create_DR(true, true);
case RemoteExecute: case RemoteExecute:
/* like Remote, but suppress output of T message */
return printtup_create_DR(false, false);
case RemoteExecuteInternal: case RemoteExecuteInternal:
return printtup_create_DR(true, false); return printtup_create_DR(dest);
case None: case None:
return &donothingDR; return &donothingDR;
@ -113,7 +113,12 @@ DestToFunction(CommandDest dest)
return &spi_printtupDR; return &spi_printtupDR;
case Tuplestore: 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 */ /* should never get here */

View File

@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
@ -656,6 +656,8 @@ pg_plan_queries(List *querytrees, bool needSnapshot)
static void static void
exec_simple_query(const char *query_string) exec_simple_query(const char *query_string)
{ {
CommandDest dest = whereToSendOutput;
DestReceiver *receiver;
MemoryContext oldcontext; MemoryContext oldcontext;
List *parsetree_list, List *parsetree_list,
*parsetree_item; *parsetree_item;
@ -682,6 +684,12 @@ exec_simple_query(const char *query_string)
if (save_log_statement_stats) if (save_log_statement_stats)
ResetUsage(); 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 * Start up a transaction command. All queries generated by the
* query_string will be in this same command block, *unless* we find a * 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); set_ps_display(commandTag);
BeginCommand(commandTag, whereToSendOutput); BeginCommand(commandTag, dest);
/* /*
* If we are in an aborted transaction, reject all commands except * 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, (void) PortalRun(portal,
FETCH_ALL, FETCH_ALL,
whereToSendOutput, receiver,
whereToSendOutput, receiver,
completionTag); completionTag);
PortalDrop(portal, false); 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 * (But a command aborted by error will not send an EndCommand
* report at all.) * report at all.)
*/ */
EndCommand(completionTag, whereToSendOutput); EndCommand(completionTag, dest);
} /* end loop over parsetrees */ } /* end loop over parsetrees */
/* /*
* If there were no parsetrees, return EmptyQueryResponse message. * If there were no parsetrees, return EmptyQueryResponse message.
*/ */
if (!parsetree_list) if (!parsetree_list)
NullCommand(whereToSendOutput); NullCommand(dest);
(*receiver->destroy) (receiver);
QueryContext = NULL; QueryContext = NULL;
@ -1282,6 +1292,7 @@ static void
exec_execute_message(const char *portal_name, int is_binary, long max_rows) exec_execute_message(const char *portal_name, int is_binary, long max_rows)
{ {
CommandDest dest; CommandDest dest;
DestReceiver *receiver;
Portal portal; Portal portal;
bool is_trans_stmt = false; bool is_trans_stmt = false;
bool is_trans_exit = 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. * Okay to run the portal.
*/ */
receiver = CreateDestReceiver(dest);
if (max_rows <= 0) if (max_rows <= 0)
max_rows = FETCH_ALL; max_rows = FETCH_ALL;
completed = PortalRun(portal, completed = PortalRun(portal,
max_rows, max_rows,
dest, receiver,
dest, receiver,
completionTag); completionTag);
(*receiver->destroy) (receiver);
if (completed) if (completed)
{ {
if (is_trans_stmt) if (is_trans_stmt)
@ -2344,7 +2359,7 @@ PostgresMain(int argc, char *argv[], const char *username)
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
puts("\nPOSTGRES backend interactive interface "); puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.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); MemoryContextSwitchTo(TopMemoryContext);
MemoryContextResetAndDeleteChildren(ErrorContext); MemoryContextResetAndDeleteChildren(ErrorContext);
CurrentPortal = NULL;
PortalContext = NULL; PortalContext = NULL;
QueryContext = NULL; QueryContext = NULL;

View File

@ -8,13 +8,14 @@
* *
* *
* IDENTIFICATION * 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 "postgres.h"
#include "executor/executor.h" #include "executor/executor.h"
#include "executor/tstoreReceiver.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "tcop/tcopprot.h" #include "tcop/tcopprot.h"
#include "tcop/pquery.h" #include "tcop/pquery.h"
@ -24,18 +25,18 @@
static uint32 RunFromStore(Portal portal, ScanDirection direction, long count, static uint32 RunFromStore(Portal portal, ScanDirection direction, long count,
CommandDest dest); DestReceiver *dest);
static long PortalRunSelect(Portal portal, bool forward, long count, static long PortalRunSelect(Portal portal, bool forward, long count,
CommandDest dest); DestReceiver *dest);
static void PortalRunUtility(Portal portal, Query *query, static void PortalRunUtility(Portal portal, Query *query,
CommandDest dest, char *completionTag); DestReceiver *dest, char *completionTag);
static void PortalRunMulti(Portal portal, static void PortalRunMulti(Portal portal,
CommandDest dest, CommandDest altdest, DestReceiver *dest, DestReceiver *altdest,
char *completionTag); char *completionTag);
static long DoPortalRunFetch(Portal portal, static long DoPortalRunFetch(Portal portal,
FetchDirection fdirection, FetchDirection fdirection,
long count, long count,
CommandDest dest); DestReceiver *dest);
static void DoPortalRewind(Portal portal); static void DoPortalRewind(Portal portal);
@ -45,7 +46,7 @@ static void DoPortalRewind(Portal portal);
QueryDesc * QueryDesc *
CreateQueryDesc(Query *parsetree, CreateQueryDesc(Query *parsetree,
Plan *plantree, Plan *plantree,
CommandDest dest, DestReceiver *dest,
const char *portalName, const char *portalName,
ParamListInfo params, ParamListInfo params,
bool doInstrument) bool doInstrument)
@ -103,7 +104,7 @@ ProcessQuery(Query *parsetree,
Plan *plan, Plan *plan,
ParamListInfo params, ParamListInfo params,
const char *portalName, const char *portalName,
CommandDest dest, DestReceiver *dest,
char *completionTag) char *completionTag)
{ {
int operation = parsetree->commandType; int operation = parsetree->commandType;
@ -123,7 +124,7 @@ ProcessQuery(Query *parsetree,
* special-cases this case. (Perhaps would be cleaner to have * special-cases this case. (Perhaps would be cleaner to have
* an additional destination type?) * an additional destination type?)
*/ */
dest = None; dest = None_Receiver;
} }
} }
@ -185,6 +186,39 @@ ProcessQuery(Query *parsetree,
FreeQueryDesc(queryDesc); 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
@ -202,7 +236,6 @@ void
PortalStart(Portal portal, ParamListInfo params) PortalStart(Portal portal, ParamListInfo params)
{ {
MemoryContext oldContext; MemoryContext oldContext;
Query *query = NULL;
QueryDesc *queryDesc; QueryDesc *queryDesc;
AssertArg(PortalIsValid(portal)); AssertArg(PortalIsValid(portal));
@ -215,23 +248,9 @@ PortalStart(Portal portal, ParamListInfo params)
portal->portalParams = 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 */ portal->strategy = ChoosePortalStrategy(portal->parseTrees);
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 */
}
}
/* /*
* Fire her up according to the strategy * 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 * Create QueryDesc in portal's context; for the moment, set
* the destination to None. * the destination to None.
*/ */
queryDesc = CreateQueryDesc(query, queryDesc = CreateQueryDesc((Query *) lfirst(portal->parseTrees),
(Plan *) lfirst(portal->planTrees), (Plan *) lfirst(portal->planTrees),
None, None_Receiver,
portal->name, portal->name,
params, params,
false); false);
@ -261,6 +280,9 @@ PortalStart(Portal portal, ParamListInfo params)
* This tells PortalCleanup to shut down the executor * This tells PortalCleanup to shut down the executor
*/ */
portal->queryDesc = queryDesc; portal->queryDesc = queryDesc;
/*
* Remember tuple descriptor
*/
portal->tupDesc = queryDesc->tupDesc; portal->tupDesc = queryDesc->tupDesc;
/* /*
* Reset cursor position data to "start of query" * Reset cursor position data to "start of query"
@ -272,10 +294,19 @@ PortalStart(Portal portal, ParamListInfo params)
break; break;
case PORTAL_UTIL_SELECT: case PORTAL_UTIL_SELECT:
/* XXX implement later */ /*
/* XXX query snapshot here? no, RunUtility will do it */ * We don't set query snapshot here, because PortalRunUtility
/* xxx what about Params? */ * will take care of it.
portal->tupDesc = NULL; */
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; break;
case PORTAL_MULTI_QUERY: case PORTAL_MULTI_QUERY:
@ -310,11 +341,11 @@ PortalStart(Portal portal, ParamListInfo params)
* suspended due to exhaustion of the count parameter. * suspended due to exhaustion of the count parameter.
*/ */
bool bool
PortalRun(Portal portal, long count, CommandDest dest, CommandDest altdest, PortalRun(Portal portal, long count,
DestReceiver *dest, DestReceiver *altdest,
char *completionTag) char *completionTag)
{ {
bool result; bool result;
Portal saveCurrentPortal;
MemoryContext savePortalContext; MemoryContext savePortalContext;
MemoryContext saveQueryContext; MemoryContext saveQueryContext;
MemoryContext oldContext; MemoryContext oldContext;
@ -336,10 +367,8 @@ PortalRun(Portal portal, long count, CommandDest dest, CommandDest altdest,
portal->portalActive = true; portal->portalActive = true;
/* /*
* Set global portal and context pointers. * Set global portal context pointers.
*/ */
saveCurrentPortal = CurrentPortal;
CurrentPortal = portal;
savePortalContext = PortalContext; savePortalContext = PortalContext;
PortalContext = PortalGetHeapMemory(portal); PortalContext = PortalGetHeapMemory(portal);
saveQueryContext = QueryContext; saveQueryContext = QueryContext;
@ -367,8 +396,14 @@ PortalRun(Portal portal, long count, CommandDest dest, CommandDest altdest,
*/ */
if (!portal->portalUtilReady) if (!portal->portalUtilReady)
{ {
DestReceiver *treceiver;
PortalCreateHoldStore(portal);
treceiver = CreateTuplestoreDestReceiver(portal->holdStore,
portal->holdContext);
PortalRunUtility(portal, lfirst(portal->parseTrees), PortalRunUtility(portal, lfirst(portal->parseTrees),
Tuplestore, NULL); treceiver, NULL);
(*treceiver->destroy) (treceiver);
portal->portalUtilReady = true; portal->portalUtilReady = true;
} }
/* /*
@ -404,7 +439,6 @@ PortalRun(Portal portal, long count, CommandDest dest, CommandDest altdest,
/* Mark portal not active */ /* Mark portal not active */
portal->portalActive = false; portal->portalActive = false;
CurrentPortal = saveCurrentPortal;
PortalContext = savePortalContext; PortalContext = savePortalContext;
QueryContext = saveQueryContext; QueryContext = saveQueryContext;
@ -431,7 +465,7 @@ long
PortalRunSelect(Portal portal, PortalRunSelect(Portal portal,
bool forward, bool forward,
long count, long count,
CommandDest dest) DestReceiver *dest)
{ {
QueryDesc *queryDesc; QueryDesc *queryDesc;
ScanDirection direction; ScanDirection direction;
@ -568,21 +602,18 @@ PortalRunSelect(Portal portal,
*/ */
static uint32 static uint32
RunFromStore(Portal portal, ScanDirection direction, long count, RunFromStore(Portal portal, ScanDirection direction, long count,
CommandDest dest) DestReceiver *dest)
{ {
DestReceiver *destfunc;
List *targetlist; List *targetlist;
long current_tuple_count = 0; long current_tuple_count = 0;
destfunc = DestToFunction(dest);
if (portal->strategy == PORTAL_ONE_SELECT) if (portal->strategy == PORTAL_ONE_SELECT)
targetlist = ((Plan *) lfirst(portal->planTrees))->targetlist; targetlist = ((Plan *) lfirst(portal->planTrees))->targetlist;
else else
targetlist = NIL; targetlist = NIL;
(*destfunc->setup) (destfunc, CMD_SELECT, portal->name, portal->tupDesc, (*dest->startup) (dest, CMD_SELECT, portal->name, portal->tupDesc,
targetlist); targetlist);
if (direction == NoMovementScanDirection) if (direction == NoMovementScanDirection)
{ {
@ -608,7 +639,7 @@ RunFromStore(Portal portal, ScanDirection direction, long count,
if (tup == NULL) if (tup == NULL)
break; break;
(*destfunc->receiveTuple) (tup, portal->tupDesc, destfunc); (*dest->receiveTuple) (tup, portal->tupDesc, dest);
if (should_free) if (should_free)
pfree(tup); pfree(tup);
@ -624,7 +655,7 @@ RunFromStore(Portal portal, ScanDirection direction, long count,
} }
} }
(*destfunc->cleanup) (destfunc); (*dest->shutdown) (dest);
return (uint32) current_tuple_count; return (uint32) current_tuple_count;
} }
@ -635,7 +666,7 @@ RunFromStore(Portal portal, ScanDirection direction, long count,
*/ */
static void static void
PortalRunUtility(Portal portal, Query *query, PortalRunUtility(Portal portal, Query *query,
CommandDest dest, char *completionTag) DestReceiver *dest, char *completionTag)
{ {
Node *utilityStmt = query->utilityStmt; Node *utilityStmt = query->utilityStmt;
@ -690,7 +721,7 @@ PortalRunUtility(Portal portal, Query *query,
*/ */
static void static void
PortalRunMulti(Portal portal, PortalRunMulti(Portal portal,
CommandDest dest, CommandDest altdest, DestReceiver *dest, DestReceiver *altdest,
char *completionTag) char *completionTag)
{ {
List *plantree_list = portal->planTrees; List *plantree_list = portal->planTrees;
@ -807,10 +838,9 @@ long
PortalRunFetch(Portal portal, PortalRunFetch(Portal portal,
FetchDirection fdirection, FetchDirection fdirection,
long count, long count,
CommandDest dest) DestReceiver *dest)
{ {
long result; long result;
Portal saveCurrentPortal;
MemoryContext savePortalContext; MemoryContext savePortalContext;
MemoryContext saveQueryContext; MemoryContext saveQueryContext;
MemoryContext oldContext; MemoryContext oldContext;
@ -828,10 +858,8 @@ PortalRunFetch(Portal portal,
portal->portalActive = true; portal->portalActive = true;
/* /*
* Set global portal and context pointers. * Set global portal context pointers.
*/ */
saveCurrentPortal = CurrentPortal;
CurrentPortal = portal;
savePortalContext = PortalContext; savePortalContext = PortalContext;
PortalContext = PortalGetHeapMemory(portal); PortalContext = PortalGetHeapMemory(portal);
saveQueryContext = QueryContext; saveQueryContext = QueryContext;
@ -856,7 +884,6 @@ PortalRunFetch(Portal portal,
/* Mark portal not active */ /* Mark portal not active */
portal->portalActive = false; portal->portalActive = false;
CurrentPortal = saveCurrentPortal;
PortalContext = savePortalContext; PortalContext = savePortalContext;
QueryContext = saveQueryContext; QueryContext = saveQueryContext;
@ -873,7 +900,7 @@ static long
DoPortalRunFetch(Portal portal, DoPortalRunFetch(Portal portal,
FetchDirection fdirection, FetchDirection fdirection,
long count, long count,
CommandDest dest) DestReceiver *dest)
{ {
bool forward; bool forward;
@ -912,7 +939,8 @@ DoPortalRunFetch(Portal portal,
{ {
DoPortalRewind(portal); DoPortalRewind(portal);
if (count > 1) if (count > 1)
PortalRunSelect(portal, true, count-1, None); PortalRunSelect(portal, true, count-1,
None_Receiver);
} }
else else
{ {
@ -921,9 +949,11 @@ DoPortalRunFetch(Portal portal,
if (portal->atEnd) if (portal->atEnd)
pos++; /* need one extra fetch if off end */ pos++; /* need one extra fetch if off end */
if (count <= pos) if (count <= pos)
PortalRunSelect(portal, false, pos-count+1, None); PortalRunSelect(portal, false, pos-count+1,
None_Receiver);
else if (count > pos+1) 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); return PortalRunSelect(portal, true, 1L, dest);
} }
@ -936,9 +966,9 @@ DoPortalRunFetch(Portal portal,
* (Is it worth considering case where count > half of size * (Is it worth considering case where count > half of size
* of query? We could rewind once we know the 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) if (count < -1)
PortalRunSelect(portal, false, -count-1, None); PortalRunSelect(portal, false, -count-1, None_Receiver);
return PortalRunSelect(portal, false, 1L, dest); return PortalRunSelect(portal, false, 1L, dest);
} }
else /* count == 0 */ else /* count == 0 */
@ -955,7 +985,7 @@ DoPortalRunFetch(Portal portal,
* Definition: advance count-1 rows, return next row (if any). * Definition: advance count-1 rows, return next row (if any).
*/ */
if (count > 1) if (count > 1)
PortalRunSelect(portal, true, count-1, None); PortalRunSelect(portal, true, count-1, None_Receiver);
return PortalRunSelect(portal, true, 1L, dest); return PortalRunSelect(portal, true, 1L, dest);
} }
else if (count < 0) else if (count < 0)
@ -965,7 +995,7 @@ DoPortalRunFetch(Portal portal,
* (if any). * (if any).
*/ */
if (count < -1) if (count < -1)
PortalRunSelect(portal, false, -count-1, None); PortalRunSelect(portal, false, -count-1, None_Receiver);
return PortalRunSelect(portal, false, 1L, dest); return PortalRunSelect(portal, false, 1L, dest);
} }
else /* count == 0 */ else /* count == 0 */
@ -995,7 +1025,7 @@ DoPortalRunFetch(Portal portal,
/* Are we sitting on a row? */ /* Are we sitting on a row? */
on_row = (!portal->atStart && !portal->atEnd); 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 */ /* MOVE 0 returns 0/1 based on if FETCH 0 would return a row */
return on_row ? 1L : 0L; return on_row ? 1L : 0L;
@ -1011,7 +1041,7 @@ DoPortalRunFetch(Portal portal,
*/ */
if (on_row) if (on_row)
{ {
PortalRunSelect(portal, false, 1L, None); PortalRunSelect(portal, false, 1L, None_Receiver);
/* Set up to fetch one row forward */ /* Set up to fetch one row forward */
count = 1; count = 1;
forward = true; forward = true;
@ -1022,7 +1052,7 @@ DoPortalRunFetch(Portal portal,
/* /*
* Optimize MOVE BACKWARD ALL into a Rewind. * 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; long result = portal->portalPos;

View File

@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * 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 "parser/parse_type.h"
#include "rewrite/rewriteDefine.h" #include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteRemove.h" #include "rewrite/rewriteRemove.h"
#include "tcop/pquery.h"
#include "tcop/utility.h" #include "tcop/utility.h"
#include "utils/acl.h" #include "utils/acl.h"
#include "utils/guc.h" #include "utils/guc.h"
@ -244,7 +245,7 @@ check_xact_readonly(Node *parsetree)
*/ */
void void
ProcessUtility(Node *parsetree, ProcessUtility(Node *parsetree,
CommandDest dest, DestReceiver *dest,
char *completionTag) char *completionTag)
{ {
check_xact_readonly(parsetree); check_xact_readonly(parsetree);
@ -310,7 +311,7 @@ ProcessUtility(Node *parsetree,
* Portal (cursor) manipulation * Portal (cursor) manipulation
*/ */
case T_DeclareCursorStmt: case T_DeclareCursorStmt:
PerformCursorOpen((DeclareCursorStmt *) parsetree, dest); PerformCursorOpen((DeclareCursorStmt *) parsetree);
break; break;
case T_ClosePortalStmt: case T_ClosePortalStmt:
@ -880,7 +881,7 @@ ProcessUtility(Node *parsetree,
{ {
VariableShowStmt *n = (VariableShowStmt *) parsetree; VariableShowStmt *n = (VariableShowStmt *) parsetree;
GetPGVariable(n->name); GetPGVariable(n->name, dest);
} }
break; 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 * CreateCommandTag

View File

@ -10,7 +10,7 @@
* Written by Peter Eisentraut <peter_e@gmx.net>. * Written by Peter Eisentraut <peter_e@gmx.net>.
* *
* IDENTIFICATION * 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 * SHOW command
*/ */
void void
GetPGVariable(const char *name) GetPGVariable(const char *name, DestReceiver *dest)
{ {
if (strcasecmp(name, "all") == 0) if (strcasecmp(name, "all") == 0)
ShowAllGUCConfig(); ShowAllGUCConfig(dest);
else 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 * SHOW command
*/ */
void void
ShowGUCConfigOption(const char *name) ShowGUCConfigOption(const char *name, DestReceiver *dest)
{ {
TupOutputState *tstate; TupOutputState *tstate;
TupleDesc tupdesc; TupleDesc tupdesc;
CommandDest dest = whereToSendOutput;
const char *varname; const char *varname;
char *value; char *value;
@ -2497,12 +2525,11 @@ ShowGUCConfigOption(const char *name)
* SHOW ALL command * SHOW ALL command
*/ */
void void
ShowAllGUCConfig(void) ShowAllGUCConfig(DestReceiver *dest)
{ {
int i; int i;
TupOutputState *tstate; TupOutputState *tstate;
TupleDesc tupdesc; TupleDesc tupdesc;
CommandDest dest = whereToSendOutput;
char *values[2]; char *values[2];
/* need a tuple descriptor representing two TEXT columns */ /* need a tuple descriptor representing two TEXT columns */

View File

@ -12,12 +12,13 @@
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/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 "postgres.h"
#include "miscadmin.h"
#include "commands/portalcmds.h" #include "commands/portalcmds.h"
#include "executor/executor.h" #include "executor/executor.h"
#include "utils/hsearch.h" #include "utils/hsearch.h"
@ -36,9 +37,6 @@
* ---------------- * ----------------
*/ */
Portal CurrentPortal = NULL; /* globally visible pointer */
#define MAX_PORTALNAME_LEN NAMEDATALEN #define MAX_PORTALNAME_LEN NAMEDATALEN
typedef struct portalhashent typedef struct portalhashent
@ -251,6 +249,38 @@ PortalDefineQuery(Portal portal,
portal->queryContext = queryContext; 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 * PortalDrop
* Destroy the portal. * Destroy the portal.
@ -279,6 +309,21 @@ PortalDrop(Portal portal, bool isError)
if (PointerIsValid(portal->cleanup)) if (PointerIsValid(portal->cleanup))
(*portal->cleanup) (portal, isError); (*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 */ /* delete tuplestore storage, if any */
if (portal->holdContext) if (portal->holdContext)
MemoryContextDelete(portal->holdContext); MemoryContextDelete(portal->holdContext);
@ -360,27 +405,12 @@ AtCommit_Portals(void)
* We are exiting the transaction that created a holdable * We are exiting the transaction that created a holdable
* cursor. Instead of dropping the portal, prepare it for * cursor. Instead of dropping the portal, prepare it for
* access by later transactions. * 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 * Note that PersistHoldablePortal() must release all
* resources used by the portal that are local to the creating * resources used by the portal that are local to the creating
* transaction. * transaction.
*/ */
PortalCreateHoldStore(portal);
PersistHoldablePortal(portal); PersistHoldablePortal(portal);
} }
else else

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: printtup.h,v 1.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" #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 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); const char *portalName, TupleDesc typeinfo, List *targetlist);
extern void debugtup(HeapTuple tuple, TupleDesc typeinfo, extern void debugtup(HeapTuple tuple, TupleDesc typeinfo,
DestReceiver *self); DestReceiver *self);
/* XXX these are really in executor/spi.c */ /* 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); 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); DestReceiver *self);
#endif /* PRINTTUP_H */ #endif /* PRINTTUP_H */

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994-5, Regents of the University of California * 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" #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, extern void ExplainOnePlan(QueryDesc *queryDesc, ExplainStmt *stmt,
TupOutputState *tstate); TupOutputState *tstate);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: 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" #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); char *completionTag);
extern void PerformPortalClose(const char *name); extern void PerformPortalClose(const char *name);

View File

@ -6,7 +6,7 @@
* *
* Copyright (c) 2002-2003, PostgreSQL Global Development Group * 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 */ /* Utility statements PREPARE, EXECUTE, DEALLOCATE, EXPLAIN EXECUTE */
extern void PrepareQuery(PrepareStmt *stmt); 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 DeallocateQuery(DeallocateStmt *stmt);
extern void ExplainExecuteQuery(ExplainStmt *stmt, TupOutputState *tstate); 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) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: execdesc.h,v 1.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. */ CmdType operation; /* CMD_SELECT, CMD_UPDATE, etc. */
Query *parsetree; /* rewritten parsetree */ Query *parsetree; /* rewritten parsetree */
Plan *plantree; /* planner's output */ 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 */ const char *portalName; /* name of portal, or NULL */
ParamListInfo params; /* param values being passed in */ ParamListInfo params; /* param values being passed in */
bool doInstrument; /* TRUE requests runtime instrumentation */ bool doInstrument; /* TRUE requests runtime instrumentation */
@ -46,7 +46,7 @@ typedef struct QueryDesc
/* in pquery.c */ /* in pquery.c */
extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree, extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
CommandDest dest, const char *portalName, DestReceiver *dest, const char *portalName,
ParamListInfo params, ParamListInfo params,
bool doInstrument); bool doInstrument);

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: executor.h,v 1.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, extern TupleTableSlot *ExecInitNullTupleSlot(EState *estate,
TupleDesc tupType); TupleDesc tupType);
extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid); extern TupleDesc ExecTypeFromTL(List *targetList, bool hasoid);
extern TupleDesc ExecCleanTypeFromTL(List *targetList, bool hasoid);
extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg); extern void UpdateChangedParamSet(PlanState *node, Bitmapset *newchg);
typedef struct TupOutputState typedef struct TupOutputState
{ {
/* use "struct" here to allow forward reference */ /* use "struct" here to allow forward reference */
struct AttInMetadata *metadata; struct AttInMetadata *metadata;
DestReceiver *destfunc; DestReceiver *dest;
} TupOutputState; } 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_tup_output(TupOutputState *tstate, char **values);
extern void do_text_output_multiline(TupOutputState *tstate, char *text); extern void do_text_output_multiline(TupOutputState *tstate, char *text);
extern void end_tup_output(TupOutputState *tstate); 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) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: 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 #define TSTORE_RECEIVER_H
#include "tcop/dest.h" #include "tcop/dest.h"
#include "utils/tuplestore.h"
extern DestReceiver *tstoreReceiverCreateDR(void);
extern DestReceiver *CreateTuplestoreDestReceiver(Tuplestorestate *tStore,
MemoryContext tContext);
#endif /* TSTORE_RECEIVER_H */ #endif /* TSTORE_RECEIVER_H */

View File

@ -21,30 +21,40 @@
* dest.c defines three functions that implement destination management: * dest.c defines three functions that implement destination management:
* *
* BeginCommand: initialize the destination at start of command. * 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. * receiver functions.
* EndCommand: clean up the destination at end of command. * EndCommand: clean up the destination at end of command.
* *
* BeginCommand/EndCommand are executed once per received SQL query. * BeginCommand/EndCommand are executed once per received SQL query.
* *
* DestToFunction, and the receiver functions it links to, are executed * CreateDestReceiver returns a receiver object appropriate to the specified
* each time we run the executor to produce tuples, which may occur * destination. The executor, as well as utility statements that can return
* multiple times per received query (eg, due to additional queries produced * tuples, are passed the resulting DestReceiver* pointer. Each executor run
* by rewrite rules). * 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 * The DestReceiver object returned by CreateDestReceiver may be a statically
* allocated object (for destination types that require no local state) * allocated object (for destination types that require no local state),
* or can be a palloc'd object that has DestReceiver as its first field * in which case destroy is a no-op. Alternatively it can be a palloc'd
* and contains additional fields (see printtup.c for an example). These * object that has DestReceiver as its first field and contains additional
* additional fields are then accessible to the DestReceiver functions * fields (see printtup.c for an example). These additional fields are then
* by casting the DestReceiver* pointer passed to them. * accessible to the DestReceiver functions by casting the DestReceiver*
* The palloc'd object is pfree'd by the DestReceiver's cleanup function. * 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) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: dest.h,v 1.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. * destination. Someday this will probably need to be improved.
* *
* Note: only the values None, Debug, Remote are legal for the global * 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. * as the destination for individual commands.
* ---------------- * ----------------
*/ */
@ -84,6 +94,11 @@ typedef enum
* DestReceiver is a base type for destination-specific local state. * DestReceiver is a base type for destination-specific local state.
* In the simplest cases, there is no state info, just the function * In the simplest cases, there is no state info, just the function
* pointers that the executor must call. * 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; typedef struct _DestReceiver DestReceiver;
@ -93,19 +108,25 @@ struct _DestReceiver
/* Called for each tuple to be output: */ /* Called for each tuple to be output: */
void (*receiveTuple) (HeapTuple tuple, TupleDesc typeinfo, void (*receiveTuple) (HeapTuple tuple, TupleDesc typeinfo,
DestReceiver *self); DestReceiver *self);
/* Initialization and teardown: */ /* Per-executor-run initialization and shutdown: */
void (*setup) (DestReceiver *self, int operation, void (*startup) (DestReceiver *self, int operation,
const char *portalName, const char *portalName,
TupleDesc typeinfo, TupleDesc typeinfo,
List *targetlist); List *targetlist);
void (*cleanup) (DestReceiver *self); 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... */ /* Private fields might appear beyond this point... */
}; };
extern DestReceiver *None_Receiver; /* permanent receiver for None */
/* The primary destination management functions */ /* The primary destination management functions */
extern void BeginCommand(const char *commandTag, CommandDest dest); 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); extern void EndCommand(const char *commandTag, CommandDest dest);
/* Additional functions that go with destination management, more or less. */ /* 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) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: 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, Plan *plan,
ParamListInfo params, ParamListInfo params,
const char *portalName, const char *portalName,
CommandDest dest, DestReceiver *dest,
char *completionTag); char *completionTag);
extern PortalStrategy ChoosePortalStrategy(List *parseTrees);
extern void PortalStart(Portal portal, ParamListInfo params); extern void PortalStart(Portal portal, ParamListInfo params);
extern bool PortalRun(Portal portal, long count, extern bool PortalRun(Portal portal, long count,
CommandDest dest, CommandDest altdest, DestReceiver *dest, DestReceiver *altdest,
char *completionTag); char *completionTag);
extern long PortalRunFetch(Portal portal, extern long PortalRunFetch(Portal portal,
FetchDirection fdirection, FetchDirection fdirection,
long count, long count,
CommandDest dest); DestReceiver *dest);
#endif /* PQUERY_H */ #endif /* PQUERY_H */

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: 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" #include "executor/execdesc.h"
extern void ProcessUtility(Node *parsetree, CommandDest dest, extern void ProcessUtility(Node *parsetree, DestReceiver *dest,
char *completionTag); char *completionTag);
extern bool UtilityReturnsTuples(Node *parsetree);
extern TupleDesc UtilityTupleDescriptor(Node *parsetree);
extern const char *CreateCommandTag(Node *parsetree); extern const char *CreateCommandTag(Node *parsetree);
#endif /* UTILITY_H */ #endif /* UTILITY_H */

View File

@ -7,13 +7,14 @@
* Copyright 2000-2003 by PostgreSQL Global Development Group * Copyright 2000-2003 by PostgreSQL Global Development Group
* Written by Peter Eisentraut <peter_e@gmx.net>. * 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 #ifndef GUC_H
#define GUC_H #define GUC_H
#include "nodes/pg_list.h" #include "nodes/pg_list.h"
#include "tcop/dest.h"
#include "utils/array.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, extern bool set_config_option(const char *name, const char *value,
GucContext context, GucSource source, GucContext context, GucSource source,
bool isLocal, bool DoIt); bool isLocal, bool DoIt);
extern void ShowGUCConfigOption(const char *name); extern void ShowGUCConfigOption(const char *name, DestReceiver *dest);
extern void ShowAllGUCConfig(void); extern void ShowAllGUCConfig(DestReceiver *dest);
extern char *GetConfigOptionByName(const char *name, const char **varname); extern char *GetConfigOptionByName(const char *name, const char **varname);
extern char *GetConfigOptionByNum(int varnum, const char **varname, bool *noshow); extern char *GetConfigOptionByNum(int varnum, const char **varname, bool *noshow);
extern int GetNumConfigOptions(void); extern int GetNumConfigOptions(void);
extern void SetPGVariable(const char *name, List *args, bool is_local); 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 void ResetPGVariable(const char *name);
extern char *flatten_set_variable_args(const char *name, List *args); 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) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: 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) #define PortalGetHeapMemory(portal) ((portal)->heap)
/* Currently executing Portal, if any */
extern DLLIMPORT Portal CurrentPortal;
/* Prototypes for functions in utils/mmgr/portalmem.c */ /* Prototypes for functions in utils/mmgr/portalmem.c */
extern void EnablePortalManager(void); extern void EnablePortalManager(void);
extern void AtCommit_Portals(void); extern void AtCommit_Portals(void);
@ -176,5 +172,6 @@ extern void PortalDefineQuery(Portal portal,
List *parseTrees, List *parseTrees,
List *planTrees, List *planTrees,
MemoryContext queryContext); MemoryContext queryContext);
extern void PortalCreateHoldStore(Portal portal);
#endif /* PORTAL_H */ #endif /* PORTAL_H */