diff -urN pgsql-2005-12-14/src/backend/commands/prepare.c pgsql-2005-12-15/src/backend/commands/prepare.c --- pgsql-2005-12-14/src/backend/commands/prepare.c 2005-11-28 17:25:49.000000000 -0800 +++ pgsql-2005-12-15/src/backend/commands/prepare.c 2005-12-14 09:06:27.000000000 -0800 @@ -10,7 +10,7 @@ * Copyright (c) 2002-2005, PostgreSQL Global Development Group * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.43 2005/11/29 01:25:49 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.44 2005/12/14 17:06:27 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -448,6 +448,30 @@ } /* + * 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; +} + +/* * Given a prepared statement that returns tuples, extract the query * targetlist. Returns NIL if the statement doesn't have a determinable * targetlist. diff -urN pgsql-2005-12-14/src/backend/executor/execQual.c pgsql-2005-12-15/src/backend/executor/execQual.c --- pgsql-2005-12-14/src/backend/executor/execQual.c 2005-11-22 10:17:10.000000000 -0800 +++ pgsql-2005-12-15/src/backend/executor/execQual.c 2005-12-14 08:28:32.000000000 -0800 @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.185 2005/11/22 18:17:10 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.186 2005/12/14 16:28:32 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -523,7 +523,7 @@ Assert(variable->varno != OUTER); slot = econtext->ecxt_scantuple; - tuple = slot->tts_tuple; + tuple = ExecFetchSlotTuple(slot); tupleDesc = slot->tts_tupleDescriptor; /* diff -urN pgsql-2005-12-14/src/backend/tcop/postgres.c pgsql-2005-12-15/src/backend/tcop/postgres.c --- pgsql-2005-12-14/src/backend/tcop/postgres.c 2005-11-22 10:17:21.000000000 -0800 +++ pgsql-2005-12-15/src/backend/tcop/postgres.c 2005-12-14 09:06:27.000000000 -0800 @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.470 2005/11/22 18:17:21 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.471 2005/12/14 17:06:27 tgl Exp $ * * NOTES * this is the "main" module of the postgres backend and @@ -1849,6 +1849,15 @@ ListCell *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); @@ -1862,6 +1871,22 @@ 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 != DestRemote) return; /* can't actually do anything... */ @@ -1902,12 +1927,36 @@ { 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 != DestRemote) return; /* can't actually do anything... */ diff -urN pgsql-2005-12-14/src/include/commands/prepare.h pgsql-2005-12-15/src/include/commands/prepare.h --- pgsql-2005-12-14/src/include/commands/prepare.h 2005-11-28 17:25:50.000000000 -0800 +++ pgsql-2005-12-15/src/include/commands/prepare.h 2005-12-14 09:06:28.000000000 -0800 @@ -6,7 +6,7 @@ * * Copyright (c) 2002-2005, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/include/commands/prepare.h,v 1.15 2005/11/29 01:25:50 tgl Exp $ + * $PostgreSQL: pgsql/src/include/commands/prepare.h,v 1.16 2005/12/14 17:06:28 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -60,6 +60,7 @@ 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); extern List *FetchPreparedStatementTargetList(PreparedStatement *stmt); #endif /* PREPARE_H */ diff -urN pgsql-2005-12-14/src/interfaces/libpq/libpq.rc pgsql-2005-12-15/src/interfaces/libpq/libpq.rc --- pgsql-2005-12-14/src/interfaces/libpq/libpq.rc 2006-09-20 10:05:18.000000000 -0700 +++ pgsql-2005-12-15/src/interfaces/libpq/libpq.rc 2006-09-19 17:31:48.000000000 -0700 @@ -1,8 +1,8 @@ #include VS_VERSION_INFO VERSIONINFO - FILEVERSION 8,2,0,6263 - PRODUCTVERSION 8,2,0,6263 + FILEVERSION 8,2,0,6262 + PRODUCTVERSION 8,2,0,6262 FILEFLAGSMASK 0x3fL FILEFLAGS 0 FILEOS VOS__WINDOWS32 diff -urN pgsql-2005-12-14/src/test/regress/expected/select.out pgsql-2005-12-15/src/test/regress/expected/select.out --- pgsql-2005-12-14/src/test/regress/expected/select.out 2005-04-06 18:51:40.000000000 -0700 +++ pgsql-2005-12-15/src/test/regress/expected/select.out 2005-12-14 08:28:32.000000000 -0800 @@ -431,3 +431,24 @@ mary | 8 (58 rows) +-- +-- Test some cases involving whole-row Var referencing a subquery +-- +select foo from (select 1) as foo; + foo +----- + (1) +(1 row) + +select foo from (select null) as foo; + foo +----- + () +(1 row) + +select foo from (select 'xyzzy',1,null) as foo; + foo +------------ + (xyzzy,1,) +(1 row) + diff -urN pgsql-2005-12-14/src/test/regress/sql/select.sql pgsql-2005-12-15/src/test/regress/sql/select.sql --- pgsql-2005-12-14/src/test/regress/sql/select.sql 2005-04-06 18:51:41.000000000 -0700 +++ pgsql-2005-12-15/src/test/regress/sql/select.sql 2005-12-14 08:28:32.000000000 -0800 @@ -104,3 +104,9 @@ -- SELECT p.name, p.age FROM person* p ORDER BY age using >, name; +-- +-- Test some cases involving whole-row Var referencing a subquery +-- +select foo from (select 1) as foo; +select foo from (select null) as foo; +select foo from (select 'xyzzy',1,null) as foo;