On Wed, Jan 26, 2005 at 05:10:09PM -0500, Tom Lane wrote: > I don't think we have a lot of choices: we have to destroy (or at least > mark FAILED) all such cursors for the time being.
I don't see a lot of difference between marking the portal FAILED and destroying it (maybe I'm looking at the wrong code). So I just took the simpler approach; patch attached. > Note that dependency tracking would not in itself be enough to solve the > problem, since the question is not merely what objects the cursor > depends on, but whether their definitions were changed in the failed > subtransaction. Talk about messy :-( Maybe we can use the shared cache invalidation mechanism for this. When a message is received that affects a relation marked as referenced by a portal, mark the portal obsolete. I don't recall the details of shared-inval right now, I may be missing something (like the time at which messages are sent. But I believe we send a message to our own backend, no?) -- Alvaro Herrera (<[EMAIL PROTECTED]>) "Always assume the user will do much worse than the stupidest thing you can imagine." (Julien PUYDT)
Index: doc/src/sgml/ref/rollback_to.sgml =================================================================== RCS file: /home/alvherre/cvs/pgsql/doc/src/sgml/ref/rollback_to.sgml,v retrieving revision 1.5 diff -c -r1.5 rollback_to.sgml *** doc/src/sgml/ref/rollback_to.sgml 27 Nov 2004 21:27:07 -0000 1.5 --- doc/src/sgml/ref/rollback_to.sgml 26 Jan 2005 21:15:18 -0000 *************** *** 74,81 **** <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 <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). --- 74,83 ---- <para> Cursors have somewhat non-transactional behavior with respect to ! savepoints. Any cursor that is opened inside the savepoint is closed ! when the savepoint is rolled back, and a cursor that is closed inside ! the savepoint remains closed if the savepoint is rolled back. ! If a 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). Index: src/backend/utils/mmgr/portalmem.c =================================================================== RCS file: /home/alvherre/cvs/pgsql/src/backend/utils/mmgr/portalmem.c,v retrieving revision 1.76 diff -c -r1.76 portalmem.c *** src/backend/utils/mmgr/portalmem.c 31 Dec 2004 22:02:48 -0000 1.76 --- src/backend/utils/mmgr/portalmem.c 26 Jan 2005 22:36:17 -0000 *************** *** 601,609 **** /* * Subtransaction abort handling for portals. * ! * Deactivate failed portals created during the failed subtransaction. * Note that per AtSubCommit_Portals, this will catch portals created * in descendants of the subtransaction too. */ void AtSubAbort_Portals(SubTransactionId mySubid, --- 601,612 ---- /* * Subtransaction abort handling for portals. * ! * Deactivate portals created during the failed subtransaction. * Note that per AtSubCommit_Portals, this will catch portals created * in descendants of the subtransaction too. + * + * Note that we don't destroy any portals here; that's done in + * AtSubCleanup_Portals. */ void AtSubAbort_Portals(SubTransactionId mySubid, *************** *** 628,663 **** * 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.) */ if (portal->status == PORTAL_ACTIVE) portal->status = PORTAL_FAILED; ! /* ! * If the portal is READY then allow it to survive into the parent ! * transaction; otherwise shut it down. ! */ ! if (portal->status == PORTAL_READY) ! { ! portal->createSubid = parentSubid; ! if (portal->resowner) ! ResourceOwnerNewParent(portal->resowner, parentXactOwner); ! } ! else { ! /* let portalcmds.c clean up the state it knows about */ ! if (PointerIsValid(portal->cleanup)) ! { ! (*portal->cleanup) (portal); ! portal->cleanup = NULL; ! } ! ! /* ! * Any resources belonging to the portal will be released in ! * the upcoming transaction-wide cleanup; they will be gone ! * before we run PortalDrop. ! */ ! portal->resowner = NULL; } } } --- 631,655 ---- * 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; ! /* let portalcmds.c clean up the state it knows about */ ! if (PointerIsValid(portal->cleanup)) { ! (*portal->cleanup) (portal); ! portal->cleanup = NULL; } + + /* + * Any resources belonging to the portal will be released in + * the upcoming transaction-wide cleanup; they will be gone + * before we run PortalDrop. + */ + portal->resowner = NULL; } }
---------------------------(end of broadcast)--------------------------- TIP 3: if posting/reading through Usenet, please send an appropriate subscribe-nomail command to [EMAIL PROTECTED] so that your message can get through to the mailing list cleanly