mirror of
https://github.com/postgres/postgres.git
synced 2025-07-03 20:02:46 +03:00
Defend against crash while processing Describe Statement or Describe Portal
messages, when client attempts to execute these outside a transaction (start one) or in a failed transaction (reject message, except for COMMIT/ROLLBACK statements which we can handle). Per report from Francisco Figueiredo Jr.
This commit is contained in:
@ -10,7 +10,7 @@
|
||||
* Copyright (c) 2002-2003, PostgreSQL Global Development Group
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.23.4.2 2004/12/13 00:17:52 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.23.4.3 2005/12/14 17:06:59 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -442,6 +442,30 @@ FetchPreparedStatementResultDesc(PreparedStatement *stmt)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Given a prepared statement, determine whether it will return tuples.
|
||||
*
|
||||
* Note: this is used rather than just testing the result of
|
||||
* FetchPreparedStatementResultDesc() because that routine can fail if
|
||||
* invoked in an aborted transaction. This one is safe to use in any
|
||||
* context. Be sure to keep the two routines in sync!
|
||||
*/
|
||||
bool
|
||||
PreparedStatementReturnsTuples(PreparedStatement *stmt)
|
||||
{
|
||||
switch (ChoosePortalStrategy(stmt->query_list))
|
||||
{
|
||||
case PORTAL_ONE_SELECT:
|
||||
case PORTAL_UTIL_SELECT:
|
||||
return true;
|
||||
|
||||
case PORTAL_MULTI_QUERY:
|
||||
/* will not return tuples */
|
||||
break;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implements the 'DEALLOCATE' utility statement: deletes the
|
||||
* specified plan from storage.
|
||||
|
@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.375.2.4 2005/11/10 00:31:59 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/tcop/postgres.c,v 1.375.2.5 2005/12/14 17:07:00 tgl Exp $
|
||||
*
|
||||
* NOTES
|
||||
* this is the "main" module of the postgres backend and
|
||||
@ -1644,6 +1644,15 @@ exec_describe_statement_message(const char *stmt_name)
|
||||
List *l;
|
||||
StringInfoData buf;
|
||||
|
||||
/*
|
||||
* Start up a transaction command. (Note that this will normally change
|
||||
* current memory context.) Nothing happens if we are already in one.
|
||||
*/
|
||||
start_xact_command();
|
||||
|
||||
/* Switch back to message context */
|
||||
MemoryContextSwitchTo(MessageContext);
|
||||
|
||||
/* Find prepared statement */
|
||||
if (stmt_name[0] != '\0')
|
||||
pstmt = FetchPreparedStatement(stmt_name, true);
|
||||
@ -1657,6 +1666,22 @@ exec_describe_statement_message(const char *stmt_name)
|
||||
errmsg("unnamed prepared statement does not exist")));
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are in aborted transaction state, we can't safely create a result
|
||||
* tupledesc, because that needs catalog accesses. Hence, refuse to
|
||||
* Describe statements that return data. (We shouldn't just refuse all
|
||||
* Describes, since that might break the ability of some clients to issue
|
||||
* COMMIT or ROLLBACK commands, if they use code that blindly Describes
|
||||
* whatever it does.) We can Describe parameters without doing anything
|
||||
* dangerous, so we don't restrict that.
|
||||
*/
|
||||
if (IsAbortedTransactionBlockState() &&
|
||||
PreparedStatementReturnsTuples(pstmt))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
|
||||
errmsg("current transaction is aborted, "
|
||||
"commands ignored until end of transaction block")));
|
||||
|
||||
if (whereToSendOutput != Remote)
|
||||
return; /* can't actually do anything... */
|
||||
|
||||
@ -1703,12 +1728,36 @@ exec_describe_portal_message(const char *portal_name)
|
||||
{
|
||||
Portal portal;
|
||||
|
||||
/*
|
||||
* Start up a transaction command. (Note that this will normally change
|
||||
* current memory context.) Nothing happens if we are already in one.
|
||||
*/
|
||||
start_xact_command();
|
||||
|
||||
/* Switch back to message context */
|
||||
MemoryContextSwitchTo(MessageContext);
|
||||
|
||||
portal = GetPortalByName(portal_name);
|
||||
if (!PortalIsValid(portal))
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_UNDEFINED_CURSOR),
|
||||
errmsg("portal \"%s\" does not exist", portal_name)));
|
||||
|
||||
/*
|
||||
* If we are in aborted transaction state, we can't run
|
||||
* SendRowDescriptionMessage(), because that needs catalog accesses.
|
||||
* Hence, refuse to Describe portals that return data. (We shouldn't just
|
||||
* refuse all Describes, since that might break the ability of some
|
||||
* clients to issue COMMIT or ROLLBACK commands, if they use code that
|
||||
* blindly Describes whatever it does.)
|
||||
*/
|
||||
if (IsAbortedTransactionBlockState() &&
|
||||
portal->tupDesc)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
|
||||
errmsg("current transaction is aborted, "
|
||||
"commands ignored until end of transaction block")));
|
||||
|
||||
if (whereToSendOutput != Remote)
|
||||
return; /* can't actually do anything... */
|
||||
|
||||
@ -2715,7 +2764,7 @@ PostgresMain(int argc, char *argv[], const char *username)
|
||||
if (!IsUnderPostmaster)
|
||||
{
|
||||
puts("\nPOSTGRES backend interactive interface ");
|
||||
puts("$Revision: 1.375.2.4 $ $Date: 2005/11/10 00:31:59 $\n");
|
||||
puts("$Revision: 1.375.2.5 $ $Date: 2005/12/14 17:07:00 $\n");
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -6,7 +6,7 @@
|
||||
*
|
||||
* Copyright (c) 2002-2003, PostgreSQL Global Development Group
|
||||
*
|
||||
* $Id: prepare.h,v 1.8 2003/08/08 21:42:40 momjian Exp $
|
||||
* $Id: prepare.h,v 1.8.4.1 2005/12/14 17:07:00 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -58,5 +58,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 bool PreparedStatementReturnsTuples(PreparedStatement *stmt);
|
||||
|
||||
#endif /* PREPARE_H */
|
||||
|
Reference in New Issue
Block a user