From e98edb5555de0197ba4ffc99b4f3db134c99a86f Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 22 Jun 2005 17:45:46 +0000 Subject: [PATCH] Fix the mechanism for reporting the original table OID and column number of columns of a query result so that it can "see through" cursors and prepared statements. Per gripe a couple months back from John DeSoi. --- src/backend/access/common/printtup.c | 16 +++------ src/backend/commands/prepare.c | 54 +++++++++++++++++++++++++++- src/backend/tcop/postgres.c | 25 ++++--------- src/backend/tcop/pquery.c | 53 ++++++++++++++++++++++++++- src/include/commands/prepare.h | 3 +- src/include/tcop/pquery.h | 4 ++- 6 files changed, 121 insertions(+), 34 deletions(-) diff --git a/src/backend/access/common/printtup.c b/src/backend/access/common/printtup.c index 78939e2bd0..9080d047fc 100644 --- a/src/backend/access/common/printtup.c +++ b/src/backend/access/common/printtup.c @@ -9,7 +9,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/access/common/printtup.c,v 1.90 2005/05/01 18:56:17 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/common/printtup.c,v 1.91 2005/06/22 17:45:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -19,6 +19,7 @@ #include "access/printtup.h" #include "libpq/libpq.h" #include "libpq/pqformat.h" +#include "tcop/pquery.h" #include "utils/lsyscache.h" #include "utils/portal.h" @@ -130,16 +131,9 @@ printtup_startup(DestReceiver *self, int operation, TupleDesc typeinfo) * descriptions, then we send back the tuple descriptor of the tuples. */ if (operation == CMD_SELECT && myState->sendDescrip) - { - List *targetlist; - - if (portal->strategy == PORTAL_ONE_SELECT) - targetlist = ((Query *) linitial(portal->parseTrees))->targetList; - else - targetlist = NIL; - - SendRowDescriptionMessage(typeinfo, targetlist, portal->formats); - } + SendRowDescriptionMessage(typeinfo, + FetchPortalTargetList(portal), + portal->formats); /* ---------------- * We could set up the derived attr info at this time, but we postpone it diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index be3416bd3e..dec3d249df 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -10,7 +10,7 @@ * Copyright (c) 2002-2005, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.39 2005/06/03 23:05:28 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.40 2005/06/22 17:45:45 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -445,6 +445,58 @@ FetchPreparedStatementResultDesc(PreparedStatement *stmt) return NULL; } +/* + * Given a prepared statement that returns tuples, extract the query + * targetlist. Returns NIL if the statement doesn't have a determinable + * targetlist. + * + * Note: do not modify the result. + * + * XXX be careful to keep this in sync with FetchPortalTargetList, + * and with UtilityReturnsTuples. + */ +List * +FetchPreparedStatementTargetList(PreparedStatement *stmt) +{ + PortalStrategy strategy = ChoosePortalStrategy(stmt->query_list); + + if (strategy == PORTAL_ONE_SELECT) + return ((Query *) linitial(stmt->query_list))->targetList; + if (strategy == PORTAL_UTIL_SELECT) + { + Node *utilityStmt; + + utilityStmt = ((Query *) linitial(stmt->query_list))->utilityStmt; + switch (nodeTag(utilityStmt)) + { + case T_FetchStmt: + { + FetchStmt *substmt = (FetchStmt *) utilityStmt; + Portal subportal; + + Assert(!substmt->ismove); + subportal = GetPortalByName(substmt->portalname); + Assert(PortalIsValid(subportal)); + return FetchPortalTargetList(subportal); + } + + case T_ExecuteStmt: + { + ExecuteStmt *substmt = (ExecuteStmt *) utilityStmt; + PreparedStatement *entry; + + Assert(!substmt->into); + entry = FetchPreparedStatement(substmt->name, true); + return FetchPreparedStatementTargetList(entry); + } + + default: + break; + } + } + return NIL; +} + /* * Implements the 'DEALLOCATE' utility statement: deletes the * specified plan from storage. diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 454bc2577e..a676edd9a9 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.449 2005/06/17 22:32:46 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.450 2005/06/22 17:45:45 tgl Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -1928,15 +1928,9 @@ exec_describe_statement_message(const char *stmt_name) */ tupdesc = FetchPreparedStatementResultDesc(pstmt); if (tupdesc) - { - List *targetlist; - - if (ChoosePortalStrategy(pstmt->query_list) == PORTAL_ONE_SELECT) - targetlist = ((Query *) linitial(pstmt->query_list))->targetList; - else - targetlist = NIL; - SendRowDescriptionMessage(tupdesc, targetlist, NULL); - } + SendRowDescriptionMessage(tupdesc, + FetchPreparedStatementTargetList(pstmt), + NULL); else pq_putemptymessage('n'); /* NoData */ @@ -1962,16 +1956,9 @@ exec_describe_portal_message(const char *portal_name) return; /* can't actually do anything... */ if (portal->tupDesc) - { - List *targetlist; - - if (portal->strategy == PORTAL_ONE_SELECT) - targetlist = ((Query *) linitial(portal->parseTrees))->targetList; - else - targetlist = NIL; - SendRowDescriptionMessage(portal->tupDesc, targetlist, + SendRowDescriptionMessage(portal->tupDesc, + FetchPortalTargetList(portal), portal->formats); - } else pq_putemptymessage('n'); /* NoData */ } diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c index 51f3df8e56..75eb75f6de 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -8,13 +8,14 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.93 2005/03/25 21:57:58 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.94 2005/06/22 17:45:46 tgl Exp $ * *------------------------------------------------------------------------- */ #include "postgres.h" +#include "commands/prepare.h" #include "commands/trigger.h" #include "executor/executor.h" #include "miscadmin.h" @@ -252,6 +253,56 @@ ChoosePortalStrategy(List *parseTrees) return strategy; } +/* + * FetchPortalTargetList + * Given a portal that returns tuples, extract the query targetlist. + * Returns NIL if the portal doesn't have a determinable targetlist. + * + * Note: do not modify the result. + * + * XXX be careful to keep this in sync with FetchPreparedStatementTargetList, + * and with UtilityReturnsTuples. + */ +List * +FetchPortalTargetList(Portal portal) +{ + if (portal->strategy == PORTAL_ONE_SELECT) + return ((Query *) linitial(portal->parseTrees))->targetList; + if (portal->strategy == PORTAL_UTIL_SELECT) + { + Node *utilityStmt; + + utilityStmt = ((Query *) linitial(portal->parseTrees))->utilityStmt; + switch (nodeTag(utilityStmt)) + { + case T_FetchStmt: + { + FetchStmt *substmt = (FetchStmt *) utilityStmt; + Portal subportal; + + Assert(!substmt->ismove); + subportal = GetPortalByName(substmt->portalname); + Assert(PortalIsValid(subportal)); + return FetchPortalTargetList(subportal); + } + + case T_ExecuteStmt: + { + ExecuteStmt *substmt = (ExecuteStmt *) utilityStmt; + PreparedStatement *entry; + + Assert(!substmt->into); + entry = FetchPreparedStatement(substmt->name, true); + return FetchPreparedStatementTargetList(entry); + } + + default: + break; + } + } + return NIL; +} + /* * PortalStart * Prepare a portal for execution. diff --git a/src/include/commands/prepare.h b/src/include/commands/prepare.h index 4a8cde5235..b6c315bd42 100644 --- a/src/include/commands/prepare.h +++ b/src/include/commands/prepare.h @@ -6,7 +6,7 @@ * * Copyright (c) 2002-2005, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/include/commands/prepare.h,v 1.13 2005/01/01 05:43:09 momjian Exp $ + * $PostgreSQL: pgsql/src/include/commands/prepare.h,v 1.14 2005/06/22 17:45:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -59,5 +59,6 @@ extern PreparedStatement *FetchPreparedStatement(const char *stmt_name, extern void DropPreparedStatement(const char *stmt_name, bool showError); extern List *FetchPreparedStatementParams(const char *stmt_name); extern TupleDesc FetchPreparedStatementResultDesc(PreparedStatement *stmt); +extern List *FetchPreparedStatementTargetList(PreparedStatement *stmt); #endif /* PREPARE_H */ diff --git a/src/include/tcop/pquery.h b/src/include/tcop/pquery.h index c3c87baa3f..da2d29aea8 100644 --- a/src/include/tcop/pquery.h +++ b/src/include/tcop/pquery.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/tcop/pquery.h,v 1.34 2004/12/31 22:03:44 pgsql Exp $ + * $PostgreSQL: pgsql/src/include/tcop/pquery.h,v 1.35 2005/06/22 17:45:46 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -22,6 +22,8 @@ extern DLLIMPORT Portal ActivePortal; extern PortalStrategy ChoosePortalStrategy(List *parseTrees); +extern List *FetchPortalTargetList(Portal portal); + extern void PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot);