aboutsummaryrefslogtreecommitdiff
path: root/src/backend/tcop
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2003-05-06 20:26:28 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2003-05-06 20:26:28 +0000
commit79913910d4b518a42c893b6dd459656798ffa591 (patch)
treef0cd5c25dff8d026b9d8d4736717a4d38c278134 /src/backend/tcop
parent299fbb4b379003557f79d2732a85ece168d04ec4 (diff)
downloadpostgresql-79913910d4b518a42c893b6dd459656798ffa591.tar.gz
postgresql-79913910d4b518a42c893b6dd459656798ffa591.zip
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.
Diffstat (limited to 'src/backend/tcop')
-rw-r--r--src/backend/tcop/dest.c43
-rw-r--r--src/backend/tcop/postgres.c34
-rw-r--r--src/backend/tcop/pquery.c164
-rw-r--r--src/backend/tcop/utility.c140
4 files changed, 281 insertions, 100 deletions
diff --git a/src/backend/tcop/dest.c b/src/backend/tcop/dest.c
index 54b5ef75c1a..bce77603f5b 100644
--- a/src/backend/tcop/dest.c
+++ b/src/backend/tcop/dest.c
@@ -8,14 +8,14 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.56 2003/05/06 00:20:33 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/dest.c,v 1.57 2003/05/06 20:26:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
/*
* INTERFACE ROUTINES
* BeginCommand - initialize the destination at start of command
- * DestToFunction - identify per-tuple processing routines
+ * CreateDestReceiver - create tuple receiver object for destination
* EndCommand - clean up the destination at end of command
* NullCommand - tell dest that an empty query string was recognized
* ReadyForQuery - tell dest that we are ready for a new query
@@ -30,7 +30,6 @@
#include "access/printtup.h"
#include "access/xact.h"
-#include "executor/tstoreReceiver.h"
#include "libpq/libpq.h"
#include "libpq/pqformat.h"
@@ -45,14 +44,15 @@ donothingReceive(HeapTuple tuple, TupleDesc typeinfo, DestReceiver *self)
}
static void
-donothingSetup(DestReceiver *self, int operation,
- const char *portalName, TupleDesc typeinfo, List *targetlist)
+donothingStartup(DestReceiver *self, int operation,
+ const char *portalName, TupleDesc typeinfo, List *targetlist)
{
}
static void
donothingCleanup(DestReceiver *self)
{
+ /* this is used for both shutdown and destroy methods */
}
/* ----------------
@@ -60,17 +60,24 @@ donothingCleanup(DestReceiver *self)
* ----------------
*/
static DestReceiver donothingDR = {
- donothingReceive, donothingSetup, donothingCleanup
+ donothingReceive, donothingStartup, donothingCleanup, donothingCleanup,
+ None
};
static DestReceiver debugtupDR = {
- debugtup, debugSetup, donothingCleanup
+ debugtup, debugStartup, donothingCleanup, donothingCleanup,
+ Debug
};
static DestReceiver spi_printtupDR = {
- spi_printtup, spi_dest_setup, donothingCleanup
+ spi_printtup, spi_dest_startup, donothingCleanup, donothingCleanup,
+ SPI
};
+/* Globally available receiver for None */
+DestReceiver *None_Receiver = &donothingDR;
+
+
/* ----------------
* BeginCommand - initialize the destination at start of command
* ----------------
@@ -82,26 +89,19 @@ BeginCommand(const char *commandTag, CommandDest dest)
}
/* ----------------
- * DestToFunction - return appropriate receiver function set for dest
+ * CreateDestReceiver - return appropriate receiver function set for dest
* ----------------
*/
DestReceiver *
-DestToFunction(CommandDest dest)
+CreateDestReceiver(CommandDest dest)
{
switch (dest)
{
case Remote:
- return printtup_create_DR(false, true);
-
case RemoteInternal:
- return printtup_create_DR(true, true);
-
case RemoteExecute:
- /* like Remote, but suppress output of T message */
- return printtup_create_DR(false, false);
-
case RemoteExecuteInternal:
- return printtup_create_DR(true, false);
+ return printtup_create_DR(dest);
case None:
return &donothingDR;
@@ -113,7 +113,12 @@ DestToFunction(CommandDest dest)
return &spi_printtupDR;
case Tuplestore:
- return tstoreReceiverCreateDR();
+ /*
+ * This is disallowed, you must use tstoreReceiver.c's
+ * specialized function to create a Tuplestore DestReceiver
+ */
+ elog(ERROR, "CreateDestReceiver: cannot handle Tuplestore");
+ break;
}
/* should never get here */
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 0ec7fcf71d8..a7dd5cb904a 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.335 2003/05/06 05:15:45 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.336 2003/05/06 20:26:27 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -656,6 +656,8 @@ pg_plan_queries(List *querytrees, bool needSnapshot)
static void
exec_simple_query(const char *query_string)
{
+ CommandDest dest = whereToSendOutput;
+ DestReceiver *receiver;
MemoryContext oldcontext;
List *parsetree_list,
*parsetree_item;
@@ -683,6 +685,12 @@ exec_simple_query(const char *query_string)
ResetUsage();
/*
+ * Create destination receiver object --- we can reuse it for all
+ * queries in the string. Note it is created in MessageContext.
+ */
+ receiver = CreateDestReceiver(dest);
+
+ /*
* Start up a transaction command. All queries generated by the
* query_string will be in this same command block, *unless* we find a
* BEGIN/COMMIT/ABORT statement; we have to force a new xact command
@@ -745,7 +753,7 @@ exec_simple_query(const char *query_string)
set_ps_display(commandTag);
- BeginCommand(commandTag, whereToSendOutput);
+ BeginCommand(commandTag, dest);
/*
* If we are in an aborted transaction, reject all commands except
@@ -819,8 +827,8 @@ exec_simple_query(const char *query_string)
(void) PortalRun(portal,
FETCH_ALL,
- whereToSendOutput,
- whereToSendOutput,
+ receiver,
+ receiver,
completionTag);
PortalDrop(portal, false);
@@ -868,14 +876,16 @@ exec_simple_query(const char *query_string)
* (But a command aborted by error will not send an EndCommand
* report at all.)
*/
- EndCommand(completionTag, whereToSendOutput);
+ EndCommand(completionTag, dest);
} /* end loop over parsetrees */
/*
* If there were no parsetrees, return EmptyQueryResponse message.
*/
if (!parsetree_list)
- NullCommand(whereToSendOutput);
+ NullCommand(dest);
+
+ (*receiver->destroy) (receiver);
QueryContext = NULL;
@@ -1282,6 +1292,7 @@ static void
exec_execute_message(const char *portal_name, int is_binary, long max_rows)
{
CommandDest dest;
+ DestReceiver *receiver;
Portal portal;
bool is_trans_stmt = false;
bool is_trans_exit = false;
@@ -1363,15 +1374,19 @@ exec_execute_message(const char *portal_name, int is_binary, long max_rows)
/*
* Okay to run the portal.
*/
+ receiver = CreateDestReceiver(dest);
+
if (max_rows <= 0)
max_rows = FETCH_ALL;
completed = PortalRun(portal,
max_rows,
- dest,
- dest,
+ receiver,
+ receiver,
completionTag);
+ (*receiver->destroy) (receiver);
+
if (completed)
{
if (is_trans_stmt)
@@ -2344,7 +2359,7 @@ PostgresMain(int argc, char *argv[], const char *username)
if (!IsUnderPostmaster)
{
puts("\nPOSTGRES backend interactive interface ");
- puts("$Revision: 1.335 $ $Date: 2003/05/06 05:15:45 $\n");
+ puts("$Revision: 1.336 $ $Date: 2003/05/06 20:26:27 $\n");
}
/*
@@ -2412,7 +2427,6 @@ PostgresMain(int argc, char *argv[], const char *username)
*/
MemoryContextSwitchTo(TopMemoryContext);
MemoryContextResetAndDeleteChildren(ErrorContext);
- CurrentPortal = NULL;
PortalContext = NULL;
QueryContext = NULL;
diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c
index 280f269c8f8..0cb7865a9f6 100644
--- a/src/backend/tcop/pquery.c
+++ b/src/backend/tcop/pquery.c
@@ -8,13 +8,14 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.61 2003/05/06 00:20:33 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.62 2003/05/06 20:26:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
#include "executor/executor.h"
+#include "executor/tstoreReceiver.h"
#include "miscadmin.h"
#include "tcop/tcopprot.h"
#include "tcop/pquery.h"
@@ -24,18 +25,18 @@
static uint32 RunFromStore(Portal portal, ScanDirection direction, long count,
- CommandDest dest);
+ DestReceiver *dest);
static long PortalRunSelect(Portal portal, bool forward, long count,
- CommandDest dest);
+ DestReceiver *dest);
static void PortalRunUtility(Portal portal, Query *query,
- CommandDest dest, char *completionTag);
+ DestReceiver *dest, char *completionTag);
static void PortalRunMulti(Portal portal,
- CommandDest dest, CommandDest altdest,
+ DestReceiver *dest, DestReceiver *altdest,
char *completionTag);
static long DoPortalRunFetch(Portal portal,
FetchDirection fdirection,
long count,
- CommandDest dest);
+ DestReceiver *dest);
static void DoPortalRewind(Portal portal);
@@ -45,7 +46,7 @@ static void DoPortalRewind(Portal portal);
QueryDesc *
CreateQueryDesc(Query *parsetree,
Plan *plantree,
- CommandDest dest,
+ DestReceiver *dest,
const char *portalName,
ParamListInfo params,
bool doInstrument)
@@ -103,7 +104,7 @@ ProcessQuery(Query *parsetree,
Plan *plan,
ParamListInfo params,
const char *portalName,
- CommandDest dest,
+ DestReceiver *dest,
char *completionTag)
{
int operation = parsetree->commandType;
@@ -123,7 +124,7 @@ ProcessQuery(Query *parsetree,
* special-cases this case. (Perhaps would be cleaner to have
* an additional destination type?)
*/
- dest = None;
+ dest = None_Receiver;
}
}
@@ -185,6 +186,39 @@ ProcessQuery(Query *parsetree,
FreeQueryDesc(queryDesc);
}
+/*
+ * ChoosePortalStrategy
+ * Select portal execution strategy given the intended query list.
+ *
+ * See the comments in portal.h.
+ */
+PortalStrategy
+ChoosePortalStrategy(List *parseTrees)
+{
+ PortalStrategy strategy;
+
+ strategy = PORTAL_MULTI_QUERY; /* default assumption */
+
+ if (length(parseTrees) == 1)
+ {
+ Query *query = (Query *) lfirst(parseTrees);
+
+ if (query->commandType == CMD_SELECT &&
+ query->canSetTag &&
+ query->into == NULL)
+ {
+ strategy = PORTAL_ONE_SELECT;
+ }
+ else if (query->commandType == CMD_UTILITY &&
+ query->canSetTag &&
+ query->utilityStmt != NULL)
+ {
+ if (UtilityReturnsTuples(query->utilityStmt))
+ strategy = PORTAL_UTIL_SELECT;
+ }
+ }
+ return strategy;
+}
/*
* PortalStart
@@ -202,7 +236,6 @@ void
PortalStart(Portal portal, ParamListInfo params)
{
MemoryContext oldContext;
- Query *query = NULL;
QueryDesc *queryDesc;
AssertArg(PortalIsValid(portal));
@@ -215,23 +248,9 @@ PortalStart(Portal portal, ParamListInfo params)
portal->portalParams = params;
/*
- * Determine the portal execution strategy (see comments in portal.h)
+ * Determine the portal execution strategy
*/
- portal->strategy = PORTAL_MULTI_QUERY; /* default assumption */
- if (length(portal->parseTrees) == 1)
- {
- query = (Query *) lfirst(portal->parseTrees);
- if (query->commandType == CMD_SELECT &&
- query->canSetTag &&
- query->into == NULL)
- portal->strategy = PORTAL_ONE_SELECT;
- else if (query->commandType == CMD_UTILITY &&
- query->canSetTag &&
- query->utilityStmt != NULL)
- {
- /* XXX check for things that can be PORTAL_UTIL_SELECT */
- }
- }
+ portal->strategy = ChoosePortalStrategy(portal->parseTrees);
/*
* Fire her up according to the strategy
@@ -247,9 +266,9 @@ PortalStart(Portal portal, ParamListInfo params)
* Create QueryDesc in portal's context; for the moment, set
* the destination to None.
*/
- queryDesc = CreateQueryDesc(query,
+ queryDesc = CreateQueryDesc((Query *) lfirst(portal->parseTrees),
(Plan *) lfirst(portal->planTrees),
- None,
+ None_Receiver,
portal->name,
params,
false);
@@ -261,6 +280,9 @@ PortalStart(Portal portal, ParamListInfo params)
* This tells PortalCleanup to shut down the executor
*/
portal->queryDesc = queryDesc;
+ /*
+ * Remember tuple descriptor
+ */
portal->tupDesc = queryDesc->tupDesc;
/*
* Reset cursor position data to "start of query"
@@ -272,10 +294,19 @@ PortalStart(Portal portal, ParamListInfo params)
break;
case PORTAL_UTIL_SELECT:
- /* XXX implement later */
- /* XXX query snapshot here? no, RunUtility will do it */
- /* xxx what about Params? */
- portal->tupDesc = NULL;
+ /*
+ * We don't set query snapshot here, because PortalRunUtility
+ * will take care of it.
+ */
+ portal->tupDesc =
+ UtilityTupleDescriptor(((Query *) lfirst(portal->parseTrees))->utilityStmt);
+ /*
+ * Reset cursor position data to "start of query"
+ */
+ portal->atStart = true;
+ portal->atEnd = false; /* allow fetches */
+ portal->portalPos = 0;
+ portal->posOverflow = false;
break;
case PORTAL_MULTI_QUERY:
@@ -310,11 +341,11 @@ PortalStart(Portal portal, ParamListInfo params)
* suspended due to exhaustion of the count parameter.
*/
bool
-PortalRun(Portal portal, long count, CommandDest dest, CommandDest altdest,
+PortalRun(Portal portal, long count,
+ DestReceiver *dest, DestReceiver *altdest,
char *completionTag)
{
bool result;
- Portal saveCurrentPortal;
MemoryContext savePortalContext;
MemoryContext saveQueryContext;
MemoryContext oldContext;
@@ -336,10 +367,8 @@ PortalRun(Portal portal, long count, CommandDest dest, CommandDest altdest,
portal->portalActive = true;
/*
- * Set global portal and context pointers.
+ * Set global portal context pointers.
*/
- saveCurrentPortal = CurrentPortal;
- CurrentPortal = portal;
savePortalContext = PortalContext;
PortalContext = PortalGetHeapMemory(portal);
saveQueryContext = QueryContext;
@@ -367,8 +396,14 @@ PortalRun(Portal portal, long count, CommandDest dest, CommandDest altdest,
*/
if (!portal->portalUtilReady)
{
+ DestReceiver *treceiver;
+
+ PortalCreateHoldStore(portal);
+ treceiver = CreateTuplestoreDestReceiver(portal->holdStore,
+ portal->holdContext);
PortalRunUtility(portal, lfirst(portal->parseTrees),
- Tuplestore, NULL);
+ treceiver, NULL);
+ (*treceiver->destroy) (treceiver);
portal->portalUtilReady = true;
}
/*
@@ -404,7 +439,6 @@ PortalRun(Portal portal, long count, CommandDest dest, CommandDest altdest,
/* Mark portal not active */
portal->portalActive = false;
- CurrentPortal = saveCurrentPortal;
PortalContext = savePortalContext;
QueryContext = saveQueryContext;
@@ -431,7 +465,7 @@ long
PortalRunSelect(Portal portal,
bool forward,
long count,
- CommandDest dest)
+ DestReceiver *dest)
{
QueryDesc *queryDesc;
ScanDirection direction;
@@ -568,21 +602,18 @@ PortalRunSelect(Portal portal,
*/
static uint32
RunFromStore(Portal portal, ScanDirection direction, long count,
- CommandDest dest)
+ DestReceiver *dest)
{
- DestReceiver *destfunc;
List *targetlist;
long current_tuple_count = 0;
- destfunc = DestToFunction(dest);
-
if (portal->strategy == PORTAL_ONE_SELECT)
targetlist = ((Plan *) lfirst(portal->planTrees))->targetlist;
else
targetlist = NIL;
- (*destfunc->setup) (destfunc, CMD_SELECT, portal->name, portal->tupDesc,
- targetlist);
+ (*dest->startup) (dest, CMD_SELECT, portal->name, portal->tupDesc,
+ targetlist);
if (direction == NoMovementScanDirection)
{
@@ -608,7 +639,7 @@ RunFromStore(Portal portal, ScanDirection direction, long count,
if (tup == NULL)
break;
- (*destfunc->receiveTuple) (tup, portal->tupDesc, destfunc);
+ (*dest->receiveTuple) (tup, portal->tupDesc, dest);
if (should_free)
pfree(tup);
@@ -624,7 +655,7 @@ RunFromStore(Portal portal, ScanDirection direction, long count,
}
}
- (*destfunc->cleanup) (destfunc);
+ (*dest->shutdown) (dest);
return (uint32) current_tuple_count;
}
@@ -635,7 +666,7 @@ RunFromStore(Portal portal, ScanDirection direction, long count,
*/
static void
PortalRunUtility(Portal portal, Query *query,
- CommandDest dest, char *completionTag)
+ DestReceiver *dest, char *completionTag)
{
Node *utilityStmt = query->utilityStmt;
@@ -690,7 +721,7 @@ PortalRunUtility(Portal portal, Query *query,
*/
static void
PortalRunMulti(Portal portal,
- CommandDest dest, CommandDest altdest,
+ DestReceiver *dest, DestReceiver *altdest,
char *completionTag)
{
List *plantree_list = portal->planTrees;
@@ -807,10 +838,9 @@ long
PortalRunFetch(Portal portal,
FetchDirection fdirection,
long count,
- CommandDest dest)
+ DestReceiver *dest)
{
long result;
- Portal saveCurrentPortal;
MemoryContext savePortalContext;
MemoryContext saveQueryContext;
MemoryContext oldContext;
@@ -828,10 +858,8 @@ PortalRunFetch(Portal portal,
portal->portalActive = true;
/*
- * Set global portal and context pointers.
+ * Set global portal context pointers.
*/
- saveCurrentPortal = CurrentPortal;
- CurrentPortal = portal;
savePortalContext = PortalContext;
PortalContext = PortalGetHeapMemory(portal);
saveQueryContext = QueryContext;
@@ -856,7 +884,6 @@ PortalRunFetch(Portal portal,
/* Mark portal not active */
portal->portalActive = false;
- CurrentPortal = saveCurrentPortal;
PortalContext = savePortalContext;
QueryContext = saveQueryContext;
@@ -873,7 +900,7 @@ static long
DoPortalRunFetch(Portal portal,
FetchDirection fdirection,
long count,
- CommandDest dest)
+ DestReceiver *dest)
{
bool forward;
@@ -912,7 +939,8 @@ DoPortalRunFetch(Portal portal,
{
DoPortalRewind(portal);
if (count > 1)
- PortalRunSelect(portal, true, count-1, None);
+ PortalRunSelect(portal, true, count-1,
+ None_Receiver);
}
else
{
@@ -921,9 +949,11 @@ DoPortalRunFetch(Portal portal,
if (portal->atEnd)
pos++; /* need one extra fetch if off end */
if (count <= pos)
- PortalRunSelect(portal, false, pos-count+1, None);
+ PortalRunSelect(portal, false, pos-count+1,
+ None_Receiver);
else if (count > pos+1)
- PortalRunSelect(portal, true, count-pos-1, None);
+ PortalRunSelect(portal, true, count-pos-1,
+ None_Receiver);
}
return PortalRunSelect(portal, true, 1L, dest);
}
@@ -936,9 +966,9 @@ DoPortalRunFetch(Portal portal,
* (Is it worth considering case where count > half of size
* of query? We could rewind once we know the size ...)
*/
- PortalRunSelect(portal, true, FETCH_ALL, None);
+ PortalRunSelect(portal, true, FETCH_ALL, None_Receiver);
if (count < -1)
- PortalRunSelect(portal, false, -count-1, None);
+ PortalRunSelect(portal, false, -count-1, None_Receiver);
return PortalRunSelect(portal, false, 1L, dest);
}
else /* count == 0 */
@@ -955,7 +985,7 @@ DoPortalRunFetch(Portal portal,
* Definition: advance count-1 rows, return next row (if any).
*/
if (count > 1)
- PortalRunSelect(portal, true, count-1, None);
+ PortalRunSelect(portal, true, count-1, None_Receiver);
return PortalRunSelect(portal, true, 1L, dest);
}
else if (count < 0)
@@ -965,7 +995,7 @@ DoPortalRunFetch(Portal portal,
* (if any).
*/
if (count < -1)
- PortalRunSelect(portal, false, -count-1, None);
+ PortalRunSelect(portal, false, -count-1, None_Receiver);
return PortalRunSelect(portal, false, 1L, dest);
}
else /* count == 0 */
@@ -995,7 +1025,7 @@ DoPortalRunFetch(Portal portal,
/* Are we sitting on a row? */
on_row = (!portal->atStart && !portal->atEnd);
- if (dest == None)
+ if (dest->mydest == None)
{
/* MOVE 0 returns 0/1 based on if FETCH 0 would return a row */
return on_row ? 1L : 0L;
@@ -1011,7 +1041,7 @@ DoPortalRunFetch(Portal portal,
*/
if (on_row)
{
- PortalRunSelect(portal, false, 1L, None);
+ PortalRunSelect(portal, false, 1L, None_Receiver);
/* Set up to fetch one row forward */
count = 1;
forward = true;
@@ -1022,7 +1052,7 @@ DoPortalRunFetch(Portal portal,
/*
* Optimize MOVE BACKWARD ALL into a Rewind.
*/
- if (!forward && count == FETCH_ALL && dest == None)
+ if (!forward && count == FETCH_ALL && dest->mydest == None)
{
long result = portal->portalPos;
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index a0431f350c8..5fce0d5e755 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -10,7 +10,7 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.198 2003/05/02 20:54:35 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.199 2003/05/06 20:26:27 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -47,6 +47,7 @@
#include "parser/parse_type.h"
#include "rewrite/rewriteDefine.h"
#include "rewrite/rewriteRemove.h"
+#include "tcop/pquery.h"
#include "tcop/utility.h"
#include "utils/acl.h"
#include "utils/guc.h"
@@ -244,7 +245,7 @@ check_xact_readonly(Node *parsetree)
*/
void
ProcessUtility(Node *parsetree,
- CommandDest dest,
+ DestReceiver *dest,
char *completionTag)
{
check_xact_readonly(parsetree);
@@ -310,7 +311,7 @@ ProcessUtility(Node *parsetree,
* Portal (cursor) manipulation
*/
case T_DeclareCursorStmt:
- PerformCursorOpen((DeclareCursorStmt *) parsetree, dest);
+ PerformCursorOpen((DeclareCursorStmt *) parsetree);
break;
case T_ClosePortalStmt:
@@ -880,7 +881,7 @@ ProcessUtility(Node *parsetree,
{
VariableShowStmt *n = (VariableShowStmt *) parsetree;
- GetPGVariable(n->name);
+ GetPGVariable(n->name, dest);
}
break;
@@ -1028,6 +1029,137 @@ ProcessUtility(Node *parsetree,
}
}
+/*
+ * UtilityReturnsTuples
+ * Return "true" if this utility statement will send output to the
+ * destination.
+ *
+ * Generally, there should be a case here for each case in ProcessUtility
+ * where "dest" is passed on.
+ */
+bool
+UtilityReturnsTuples(Node *parsetree)
+{
+ switch (nodeTag(parsetree))
+ {
+ case T_FetchStmt:
+ {
+ FetchStmt *stmt = (FetchStmt *) parsetree;
+ Portal portal;
+
+ if (stmt->ismove)
+ return false;
+ portal = GetPortalByName(stmt->portalname);
+ if (!PortalIsValid(portal))
+ return false; /* not our business to raise error */
+ /*
+ * Note: if portal contains multiple statements then it's
+ * possible some of them will return tuples, but we don't
+ * handle that case here.
+ */
+ return portal->tupDesc ? true : false;
+ }
+
+ case T_ExecuteStmt:
+ {
+ ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
+ PreparedStatement *entry;
+
+ if (stmt->into)
+ return false;
+ entry = FetchPreparedStatement(stmt->name, false);
+ if (!entry)
+ return false; /* not our business to raise error */
+ switch (ChoosePortalStrategy(entry->query_list))
+ {
+ case PORTAL_ONE_SELECT:
+ return true;
+ case PORTAL_UTIL_SELECT:
+ return true;
+ case PORTAL_MULTI_QUERY:
+ /* can't figure it out, per note above */
+ break;
+ }
+ return false;
+ }
+
+ case T_ExplainStmt:
+ return true;
+
+ case T_VariableShowStmt:
+ return true;
+
+ default:
+ return false;
+ }
+}
+
+/*
+ * UtilityTupleDescriptor
+ * Fetch the actual output tuple descriptor for a utility statement
+ * for which UtilityReturnsTuples() previously returned "true".
+ *
+ * The returned descriptor is created in (or copied into) the current memory
+ * context.
+ */
+TupleDesc
+UtilityTupleDescriptor(Node *parsetree)
+{
+ switch (nodeTag(parsetree))
+ {
+ case T_FetchStmt:
+ {
+ FetchStmt *stmt = (FetchStmt *) parsetree;
+ Portal portal;
+
+ if (stmt->ismove)
+ return NULL;
+ portal = GetPortalByName(stmt->portalname);
+ if (!PortalIsValid(portal))
+ return NULL; /* not our business to raise error */
+ return CreateTupleDescCopy(portal->tupDesc);
+ }
+
+ case T_ExecuteStmt:
+ {
+ ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
+ PreparedStatement *entry;
+ Query *query;
+
+ if (stmt->into)
+ return NULL;
+ entry = FetchPreparedStatement(stmt->name, false);
+ if (!entry)
+ return NULL; /* not our business to raise error */
+ switch (ChoosePortalStrategy(entry->query_list))
+ {
+ case PORTAL_ONE_SELECT:
+ query = (Query *) lfirst(entry->query_list);
+ return ExecCleanTypeFromTL(query->targetList, false);
+ case PORTAL_UTIL_SELECT:
+ query = (Query *) lfirst(entry->query_list);
+ return UtilityTupleDescriptor(query->utilityStmt);
+ case PORTAL_MULTI_QUERY:
+ break;
+ }
+ return NULL;
+ }
+
+ case T_ExplainStmt:
+ return ExplainResultDesc((ExplainStmt *) parsetree);
+
+ case T_VariableShowStmt:
+ {
+ VariableShowStmt *n = (VariableShowStmt *) parsetree;
+
+ return GetPGVariableResultDesc(n->name);
+ }
+
+ default:
+ return NULL;
+ }
+}
+
/*
* CreateCommandTag