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