Commit 755d1917 authored by Tom Lane's avatar Tom Lane

Add display of eventual result RowDescription (if any) to the output

of Describe on a prepared statement.  This was in the original 3.0
protocol proposal, but I took it out for reasons that seemed good at
the time.  Put it back per yesterday's pghackers discussion.
parent 8f6a6b7e
<!-- $Header: /cvsroot/pgsql/doc/src/sgml/protocol.sgml,v 1.34 2003/05/05 00:44:55 tgl Exp $ --> <!-- $Header: /cvsroot/pgsql/doc/src/sgml/protocol.sgml,v 1.35 2003/05/06 21:51:41 tgl Exp $ -->
<chapter id="protocol"> <chapter id="protocol">
<title>Frontend/Backend Protocol</title> <title>Frontend/Backend Protocol</title>
...@@ -149,7 +149,8 @@ ...@@ -149,7 +149,8 @@
<firstterm>bind</> step, which creates a portal given a prepared <firstterm>bind</> step, which creates a portal given a prepared
statement and values for any needed parameters; and an statement and values for any needed parameters; and an
<firstterm>execute</> step that runs a portal's query. In the case of <firstterm>execute</> step that runs a portal's query. In the case of
a <command>SELECT</> query, the execute step can be told to fetch only a query that returns rows (<command>SELECT</>, <command>SHOW</>, etc),
the execute step can be told to fetch only
a limited number of rows, so that multiple execute steps may be needed a limited number of rows, so that multiple execute steps may be needed
to complete the operation. to complete the operation.
</para> </para>
...@@ -456,7 +457,7 @@ ...@@ -456,7 +457,7 @@
<ListItem> <ListItem>
<Para> <Para>
Indicates that rows are about to be returned in response to Indicates that rows are about to be returned in response to
a <command>SELECT</command> or <command>FETCH</command> query. a <command>SELECT</command>, <command>FETCH</command>, etc query.
The message contents describe the layout of the rows. This The message contents describe the layout of the rows. This
will be followed by a DataRow or BinaryRow message (depending on will be followed by a DataRow or BinaryRow message (depending on
whether a binary cursor was specified) for each row being returned whether a binary cursor was specified) for each row being returned
...@@ -512,8 +513,8 @@ ...@@ -512,8 +513,8 @@
</Para> </Para>
<Para> <Para>
The response to a <command>SELECT</>, <command>FETCH</>, or The response to a <command>SELECT</> query (or other queries that
<command>SHOW</> query return rowsets, such as <command>EXPLAIN</> or <command>SHOW</>)
normally consists of RowDescription, zero or more normally consists of RowDescription, zero or more
DataRow or BinaryRow messages, and then CommandComplete. DataRow or BinaryRow messages, and then CommandComplete.
<command>COPY</> to or from the frontend invokes special protocol <command>COPY</> to or from the frontend invokes special protocol
...@@ -632,8 +633,8 @@ ...@@ -632,8 +633,8 @@
unnamed portal), the desired output format (text or binary), and unnamed portal), the desired output format (text or binary), and
a maximum result-row count (zero meaning <quote>fetch all rows</>). a maximum result-row count (zero meaning <quote>fetch all rows</>).
The output format and result-row count are only meaningful for portals The output format and result-row count are only meaningful for portals
containing SELECT commands; they are ignored for other types of commands. containing commands that return rowsets; they are ignored for other types
The possible of commands. The possible
responses to Execute are the same as those described above for queries responses to Execute are the same as those described above for queries
issued via simple query protocol, except that Execute doesn't cause issued via simple query protocol, except that Execute doesn't cause
ReadyForQuery to be issued. Also, the choice between text and binary ReadyForQuery to be issued. Also, the choice between text and binary
...@@ -689,20 +690,27 @@ ...@@ -689,20 +690,27 @@
portal (or an empty string for the unnamed portal). The response is a portal (or an empty string for the unnamed portal). The response is a
RowDescription message describing the rows that will be returned by RowDescription message describing the rows that will be returned by
executing the portal; or a NoData message if the portal does not contain a executing the portal; or a NoData message if the portal does not contain a
SELECT-type query; or ErrorResponse if there is no such portal. In most query that will return rows; or ErrorResponse if there is no such portal.
situations the frontend will want to issue this message before issuing
Execute, to obtain a description of the results it will get back.
</para> </para>
<para> <para>
The Describe message (statement variant) specifies the name of an existing The Describe message (statement variant) specifies the name of an existing
prepared statement (or an empty string for the unnamed prepared prepared statement (or an empty string for the unnamed prepared
statement). The response is a ParameterDescription message describing the statement). The response is a ParameterDescription message describing the
parameters needed by the statement. ErrorResponse is issued if there is parameters needed by the statement (if any), followed by a RowDescription
no such prepared statement. This message may be useful if the client message describing the rows that will be returned when the statement is
library is uncertain about the parameters needed by a prepared statement. eventually executed (or NoData if the statement will not return rows).
ErrorResponse is issued if there is no such prepared statement.
</para> </para>
<tip>
<para>
In most scenarios the frontend should issue one or the other variant
of Describe before issuing Execute, to ensure that it knows how to
interpret the results it will get back.
</para>
</tip>
<para> <para>
The Close message closes an existing prepared statement or portal The Close message closes an existing prepared statement or portal
and releases resources. It is not an error to issue Close against and releases resources. It is not an error to issue Close against
...@@ -2563,7 +2571,7 @@ Execute (F) ...@@ -2563,7 +2571,7 @@ Execute (F)
<ListItem> <ListItem>
<Para> <Para>
Maximum number of rows to return, if portal contains Maximum number of rows to return, if portal contains
a SELECT or FETCH query (ignored otherwise). Zero a query that returns rows (ignored otherwise). Zero
denotes <quote>no limit</>. denotes <quote>no limit</>.
</Para> </Para>
</ListItem> </ListItem>
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Copyright (c) 2002-2003, PostgreSQL Global Development Group * Copyright (c) 2002-2003, PostgreSQL Global Development Group
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.16 2003/05/06 20:26:26 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.17 2003/05/06 21:51:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -393,6 +393,34 @@ FetchPreparedStatementParams(const char *stmt_name) ...@@ -393,6 +393,34 @@ FetchPreparedStatementParams(const char *stmt_name)
return entry->argtype_list; return entry->argtype_list;
} }
/*
* Given a prepared statement, determine the result tupledesc it will
* produce. Returns NULL if the execution will not return tuples.
*
* Note: the result is created or copied into current memory context.
*/
TupleDesc
FetchPreparedStatementResultDesc(PreparedStatement *stmt)
{
Query *query;
switch (ChoosePortalStrategy(stmt->query_list))
{
case PORTAL_ONE_SELECT:
query = (Query *) lfirst(stmt->query_list);
return ExecCleanTypeFromTL(query->targetList, false);
case PORTAL_UTIL_SELECT:
query = (Query *) lfirst(stmt->query_list);
return UtilityTupleDescriptor(query->utilityStmt);
case PORTAL_MULTI_QUERY:
/* will not return tuples */
break;
}
return NULL;
}
/* /*
* Implements the 'DEALLOCATE' utility statement: deletes the * Implements the 'DEALLOCATE' utility statement: deletes the
* specified plan from storage. * specified plan from storage.
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.336 2003/05/06 20:26:27 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.337 2003/05/06 21:51:41 tgl Exp $
* *
* NOTES * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
...@@ -1428,6 +1428,7 @@ static void ...@@ -1428,6 +1428,7 @@ static void
exec_describe_statement_message(const char *stmt_name) exec_describe_statement_message(const char *stmt_name)
{ {
PreparedStatement *pstmt; PreparedStatement *pstmt;
TupleDesc tupdesc;
List *l; List *l;
StringInfoData buf; StringInfoData buf;
...@@ -1445,6 +1446,9 @@ exec_describe_statement_message(const char *stmt_name) ...@@ -1445,6 +1446,9 @@ exec_describe_statement_message(const char *stmt_name)
if (whereToSendOutput != Remote) if (whereToSendOutput != Remote)
return; /* can't actually do anything... */ return; /* can't actually do anything... */
/*
* First describe the parameters...
*/
pq_beginmessage(&buf, 't'); /* parameter description message type */ pq_beginmessage(&buf, 't'); /* parameter description message type */
pq_sendint(&buf, length(pstmt->argtype_list), 4); pq_sendint(&buf, length(pstmt->argtype_list), 4);
...@@ -1455,6 +1459,24 @@ exec_describe_statement_message(const char *stmt_name) ...@@ -1455,6 +1459,24 @@ exec_describe_statement_message(const char *stmt_name)
pq_sendint(&buf, (int) ptype, 4); pq_sendint(&buf, (int) ptype, 4);
} }
pq_endmessage(&buf); pq_endmessage(&buf);
/*
* Next send RowDescription or NoData to describe the result...
*/
tupdesc = FetchPreparedStatementResultDesc(pstmt);
if (tupdesc)
{
List *targetlist;
if (ChoosePortalStrategy(pstmt->query_list) == PORTAL_ONE_SELECT)
targetlist = ((Query *) lfirst(pstmt->query_list))->targetList;
else
targetlist = NIL;
SendRowDescriptionMessage(tupdesc, targetlist);
}
else
pq_putemptymessage('n'); /* NoData */
} }
/* /*
...@@ -2359,7 +2381,7 @@ PostgresMain(int argc, char *argv[], const char *username) ...@@ -2359,7 +2381,7 @@ PostgresMain(int argc, char *argv[], const char *username)
if (!IsUnderPostmaster) if (!IsUnderPostmaster)
{ {
puts("\nPOSTGRES backend interactive interface "); puts("\nPOSTGRES backend interactive interface ");
puts("$Revision: 1.336 $ $Date: 2003/05/06 20:26:27 $\n"); puts("$Revision: 1.337 $ $Date: 2003/05/06 21:51:41 $\n");
} }
/* /*
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.199 2003/05/06 20:26:27 tgl Exp $ * $Header: /cvsroot/pgsql/src/backend/tcop/utility.c,v 1.200 2003/05/06 21:51:41 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1052,11 +1052,6 @@ UtilityReturnsTuples(Node *parsetree) ...@@ -1052,11 +1052,6 @@ UtilityReturnsTuples(Node *parsetree)
portal = GetPortalByName(stmt->portalname); portal = GetPortalByName(stmt->portalname);
if (!PortalIsValid(portal)) if (!PortalIsValid(portal))
return false; /* not our business to raise error */ 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; return portal->tupDesc ? true : false;
} }
...@@ -1077,7 +1072,7 @@ UtilityReturnsTuples(Node *parsetree) ...@@ -1077,7 +1072,7 @@ UtilityReturnsTuples(Node *parsetree)
case PORTAL_UTIL_SELECT: case PORTAL_UTIL_SELECT:
return true; return true;
case PORTAL_MULTI_QUERY: case PORTAL_MULTI_QUERY:
/* can't figure it out, per note above */ /* will not return tuples */
break; break;
} }
return false; return false;
...@@ -1124,25 +1119,13 @@ UtilityTupleDescriptor(Node *parsetree) ...@@ -1124,25 +1119,13 @@ UtilityTupleDescriptor(Node *parsetree)
{ {
ExecuteStmt *stmt = (ExecuteStmt *) parsetree; ExecuteStmt *stmt = (ExecuteStmt *) parsetree;
PreparedStatement *entry; PreparedStatement *entry;
Query *query;
if (stmt->into) if (stmt->into)
return NULL; return NULL;
entry = FetchPreparedStatement(stmt->name, false); entry = FetchPreparedStatement(stmt->name, false);
if (!entry) if (!entry)
return NULL; /* not our business to raise error */ return NULL; /* not our business to raise error */
switch (ChoosePortalStrategy(entry->query_list)) return FetchPreparedStatementResultDesc(entry);
{
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: case T_ExplainStmt:
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* *
* Copyright (c) 2002-2003, PostgreSQL Global Development Group * Copyright (c) 2002-2003, PostgreSQL Global Development Group
* *
* $Id: prepare.h,v 1.5 2003/05/06 20:26:27 tgl Exp $ * $Id: prepare.h,v 1.6 2003/05/06 21:51:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -57,5 +57,6 @@ extern PreparedStatement *FetchPreparedStatement(const char *stmt_name, ...@@ -57,5 +57,6 @@ extern PreparedStatement *FetchPreparedStatement(const char *stmt_name,
bool throwError); bool throwError);
extern void DropPreparedStatement(const char *stmt_name, bool showError); extern void DropPreparedStatement(const char *stmt_name, bool showError);
extern List *FetchPreparedStatementParams(const char *stmt_name); extern List *FetchPreparedStatementParams(const char *stmt_name);
extern TupleDesc FetchPreparedStatementResultDesc(PreparedStatement *stmt);
#endif /* PREPARE_H */ #endif /* PREPARE_H */
...@@ -9,7 +9,7 @@ ...@@ -9,7 +9,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: pqcomm.h,v 1.82 2003/05/05 00:44:56 tgl Exp $ * $Id: pqcomm.h,v 1.83 2003/05/06 21:51:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -106,7 +106,7 @@ typedef union SockAddr ...@@ -106,7 +106,7 @@ typedef union SockAddr
/* The earliest and latest frontend/backend protocol version supported. */ /* The earliest and latest frontend/backend protocol version supported. */
#define PG_PROTOCOL_EARLIEST PG_PROTOCOL(1,0) #define PG_PROTOCOL_EARLIEST PG_PROTOCOL(1,0)
#define PG_PROTOCOL_LATEST PG_PROTOCOL(3,106) /* XXX temporary value */ #define PG_PROTOCOL_LATEST PG_PROTOCOL(3,107) /* XXX temporary value */
typedef uint32 ProtocolVersion; /* FE/BE protocol version number */ typedef uint32 ProtocolVersion; /* FE/BE protocol version number */
......
...@@ -12,7 +12,7 @@ ...@@ -12,7 +12,7 @@
* Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $Id: libpq-int.h,v 1.67 2003/05/05 00:44:56 tgl Exp $ * $Id: libpq-int.h,v 1.68 2003/05/06 21:51:42 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -56,7 +56,7 @@ typedef int ssize_t; /* ssize_t doesn't exist in VC (atleast ...@@ -56,7 +56,7 @@ typedef int ssize_t; /* ssize_t doesn't exist in VC (atleast
* pqcomm.h describe what the backend knows, not what libpq knows. * pqcomm.h describe what the backend knows, not what libpq knows.
*/ */
#define PG_PROTOCOL_LIBPQ PG_PROTOCOL(3,106) /* XXX temporary value */ #define PG_PROTOCOL_LIBPQ PG_PROTOCOL(3,107) /* XXX temporary value */
/* /*
* POSTGRES backend dependent Constants. * POSTGRES backend dependent Constants.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment