diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2005-01-26 23:20:37 +0000 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2005-01-26 23:20:37 +0000 |
commit | aa060cd7140c63514ef67fac552fafdd1ece7efc (patch) | |
tree | c99d516f581c8a112cf9132e54e3755497c4af9a | |
parent | 1ded77722dc7882e924c667520473004a7443ffc (diff) | |
download | postgresql-aa060cd7140c63514ef67fac552fafdd1ece7efc.tar.gz |
Close all cursors created during a failed subtransaction. This is needed
to avoid problems when a cursor depends on objects created or changed in
the same subtransaction. We'd like to do better someday, but this seems
the only workable answer for 8.0.1.
-rw-r--r-- | doc/src/sgml/ref/rollback_to.sgml | 8 | ||||
-rw-r--r-- | src/backend/utils/mmgr/portalmem.c | 16 |
2 files changed, 19 insertions, 5 deletions
diff --git a/doc/src/sgml/ref/rollback_to.sgml b/doc/src/sgml/ref/rollback_to.sgml index 0b87dc1a6b..aa204e2f9a 100644 --- a/doc/src/sgml/ref/rollback_to.sgml +++ b/doc/src/sgml/ref/rollback_to.sgml @@ -1,5 +1,5 @@ <!-- -$PostgreSQL: pgsql/doc/src/sgml/ref/rollback_to.sgml,v 1.5 2004/11/27 21:27:07 petere Exp $ +$PostgreSQL: pgsql/doc/src/sgml/ref/rollback_to.sgml,v 1.5.4.1 2005/01/26 23:20:36 tgl Exp $ PostgreSQL documentation --> @@ -74,11 +74,13 @@ ROLLBACK [ WORK | TRANSACTION ] TO [ SAVEPOINT ] <replaceable>savepoint_name</re <para> Cursors have somewhat non-transactional behavior with respect to - savepoints. Any cursor that is opened inside the savepoint is not closed - when the savepoint is rolled back. If a cursor is affected by a + savepoints. Any cursor that is opened inside a savepoint will be closed + when the savepoint is rolled back. If a previously opened cursor is + affected by a <command>FETCH</> command inside a savepoint that is later rolled back, the cursor position remains at the position that <command>FETCH</> left it pointing to (that is, <command>FETCH</> is not rolled back). + Closing a cursor is not undone by rolling back, either. A cursor whose execution causes a transaction to abort is put in a can't-execute state, so while the transaction can be restored using <command>ROLLBACK TO SAVEPOINT</>, the cursor can no longer be used. diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c index eb6635f6e1..8142a3bcca 100644 --- a/src/backend/utils/mmgr/portalmem.c +++ b/src/backend/utils/mmgr/portalmem.c @@ -12,7 +12,7 @@ * Portions Copyright (c) 1994, Regents of the University of California * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.76 2004/12/31 22:02:48 pgsql Exp $ + * $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.76.4.1 2005/01/26 23:20:37 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -601,9 +601,11 @@ AtSubCommit_Portals(SubTransactionId mySubid, /* * Subtransaction abort handling for portals. * - * Deactivate failed portals created during the failed subtransaction. + * Deactivate portals created during the failed subtransaction. * Note that per AtSubCommit_Portals, this will catch portals created * in descendants of the subtransaction too. + * + * We don't destroy any portals here; that's done in AtSubCleanup_Portals. */ void AtSubAbort_Portals(SubTransactionId mySubid, @@ -628,6 +630,8 @@ AtSubAbort_Portals(SubTransactionId mySubid, * will go FAILED if the underlying cursor fails. (Note we do NOT * want to do this to upper-level portals, since they may be able * to continue.) + * + * This is only needed to dodge the sanity check in PortalDrop. */ if (portal->status == PORTAL_ACTIVE) portal->status = PORTAL_FAILED; @@ -635,7 +639,14 @@ AtSubAbort_Portals(SubTransactionId mySubid, /* * If the portal is READY then allow it to survive into the parent * transaction; otherwise shut it down. + * + * Currently, we can't actually support that because the portal's + * query might refer to objects created or changed in the failed + * subtransaction, leading to crashes if execution is resumed. + * So, even READY portals are deleted. It would be nice to detect + * whether the query actually depends on any such object, instead. */ +#ifdef NOT_USED if (portal->status == PORTAL_READY) { portal->createSubid = parentSubid; @@ -643,6 +654,7 @@ AtSubAbort_Portals(SubTransactionId mySubid, ResourceOwnerNewParent(portal->resowner, parentXactOwner); } else +#endif { /* let portalcmds.c clean up the state it knows about */ if (PointerIsValid(portal->cleanup)) |