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

Reply via email to