summaryrefslogtreecommitdiff
path: root/src/backend/tcop
diff options
context:
space:
mode:
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 54b5ef75c1..bce77603f5 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 0ec7fcf71d..a7dd5cb904 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 280f269c8f..0cb7865a9f 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 a0431f350c..5fce0d5e75 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