diff options
Diffstat (limited to 'src/backend/tcop')
| -rw-r--r-- | src/backend/tcop/dest.c | 43 | ||||
| -rw-r--r-- | src/backend/tcop/postgres.c | 34 | ||||
| -rw-r--r-- | src/backend/tcop/pquery.c | 164 | ||||
| -rw-r--r-- | src/backend/tcop/utility.c | 140 |
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 |
