1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-16 06:01:02 +03:00

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

@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.14 2003/05/05 00:44:55 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/commands/portalcmds.c,v 1.15 2003/05/06 20:26:26 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -23,9 +23,9 @@
#include <limits.h>
#include "miscadmin.h"
#include "commands/portalcmds.h"
#include "executor/executor.h"
#include "executor/tstoreReceiver.h"
#include "optimizer/planner.h"
#include "rewrite/rewriteHandler.h"
#include "tcop/pquery.h"
@ -37,7 +37,7 @@
* Execute SQL DECLARE CURSOR command.
*/
void
PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest)
PerformCursorOpen(DeclareCursorStmt *stmt)
{
List *rewritten;
Query *query;
@ -142,9 +142,10 @@ PerformCursorOpen(DeclareCursorStmt *stmt, CommandDest dest)
*/
void
PerformPortalFetch(FetchStmt *stmt,
CommandDest dest,
DestReceiver *dest,
char *completionTag)
{
DestReceiver *mydest = dest;
Portal portal;
long nprocessed;
@ -168,7 +169,7 @@ PerformPortalFetch(FetchStmt *stmt,
}
/*
* Adjust dest if needed. MOVE wants dest = None.
* Adjust dest if needed. MOVE wants destination None.
*
* If fetching from a binary cursor and the requested destination is
* Remote, change it to RemoteInternal. Note we do NOT change if the
@ -176,21 +177,26 @@ PerformPortalFetch(FetchStmt *stmt,
* specification wins out over the cursor's type.
*/
if (stmt->ismove)
dest = None;
else if (dest == Remote && (portal->cursorOptions & CURSOR_OPT_BINARY))
dest = RemoteInternal;
mydest = CreateDestReceiver(None);
else if (dest->mydest == Remote &&
(portal->cursorOptions & CURSOR_OPT_BINARY))
mydest = CreateDestReceiver(RemoteInternal);
/* Do it */
nprocessed = PortalRunFetch(portal,
stmt->direction,
stmt->howMany,
dest);
mydest);
/* Return command status if wanted */
if (completionTag)
snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %ld",
stmt->ismove ? "MOVE" : "FETCH",
nprocessed);
/* Clean up if we created a local destination */
if (mydest != dest)
(mydest->destroy) (mydest);
}
/*
@ -243,21 +249,6 @@ PortalCleanup(Portal portal, bool isError)
AssertArg(PortalIsValid(portal));
AssertArg(portal->cleanup == PortalCleanup);
/*
* Delete tuplestore if present. (Note: portalmem.c is responsible
* for removing holdContext.) We should do this even under error
* conditions; since the tuplestore would have been using cross-
* transaction storage, its temp files need to be explicitly deleted.
*/
if (portal->holdStore)
{
MemoryContext oldcontext;
oldcontext = MemoryContextSwitchTo(portal->holdContext);
tuplestore_end(portal->holdStore);
MemoryContextSwitchTo(oldcontext);
portal->holdStore = NULL;
}
/*
* Shut down executor, if still running. We skip this during error
* abort, since other mechanisms will take care of releasing executor
@ -284,7 +275,6 @@ void
PersistHoldablePortal(Portal portal)
{
QueryDesc *queryDesc = PortalGetQueryDesc(portal);
Portal saveCurrentPortal;
MemoryContext savePortalContext;
MemoryContext saveQueryContext;
MemoryContext oldcxt;
@ -294,26 +284,22 @@ PersistHoldablePortal(Portal portal)
* inside the transaction that originally created it.
*/
Assert(portal->createXact == GetCurrentTransactionId());
Assert(portal->holdStore == NULL);
Assert(queryDesc != NULL);
Assert(portal->portalReady);
Assert(!portal->portalDone);
/*
* This context is used to store the tuple set.
* Caller must have created it already.
* Caller must have created the tuplestore already.
*/
Assert(portal->holdContext != NULL);
oldcxt = MemoryContextSwitchTo(portal->holdContext);
/* XXX: Should SortMem be used for this? */
portal->holdStore = tuplestore_begin_heap(true, true, SortMem);
Assert(portal->holdStore != NULL);
/*
* Before closing down the executor, we must copy the tupdesc, since
* it was created in executor memory. Note we are copying it into
* the holdContext.
* Before closing down the executor, we must copy the tupdesc into
* long-term memory, since it was created in executor memory.
*/
oldcxt = MemoryContextSwitchTo(portal->holdContext);
portal->tupDesc = CreateTupleDescCopy(portal->tupDesc);
MemoryContextSwitchTo(oldcxt);
@ -326,10 +312,8 @@ PersistHoldablePortal(Portal portal)
portal->portalActive = true;
/*
* Set global portal and context pointers.
* Set global portal context pointers.
*/
saveCurrentPortal = CurrentPortal;
CurrentPortal = portal;
savePortalContext = PortalContext;
PortalContext = PortalGetHeapMemory(portal);
saveQueryContext = QueryContext;
@ -344,12 +328,16 @@ PersistHoldablePortal(Portal portal)
*/
ExecutorRewind(queryDesc);
/* Set the destination to output to the tuplestore */
queryDesc->dest = Tuplestore;
/* Change the destination to output to the tuplestore */
queryDesc->dest = CreateTuplestoreDestReceiver(portal->holdStore,
portal->holdContext);
/* Fetch the result set into the tuplestore */
ExecutorRun(queryDesc, ForwardScanDirection, 0L);
(*queryDesc->dest->destroy) (queryDesc->dest);
queryDesc->dest = NULL;
/*
* Now shut down the inner executor.
*/
@ -359,7 +347,6 @@ PersistHoldablePortal(Portal portal)
/* Mark portal not active */
portal->portalActive = false;
CurrentPortal = saveCurrentPortal;
PortalContext = savePortalContext;
QueryContext = saveQueryContext;