On Tue, Jan 25, 2005 at 12:32:57PM -0500, Tom Lane wrote:
> So the right fix might involve putting the portal into PORTAL_FAILED
> state rather than just zapping it completely.
Strangely, the code comes up simpler after the fix. Patch attached.
Regression test pass. Additionaly I tried both cases mentioned in this
thread; maybe it's worthy to add tests for them too.
alvherre=# begin;
BEGIN
alvherre=# savepoint x;
SAVEPOINT
alvherre=# create table abc (a int);
CREATE TABLE
alvherre=# insert into abc values (5);
INSERT 33616 1
alvherre=# declare foo cursor for select * from abc;
DECLARE CURSOR
alvherre=# rollback to x;
ROLLBACK
alvherre=# fetch from foo; -- hits an Assert()
ERROR: no existe el cursor �foo�
alvherre=# commit;
ROLLBACK
alvherre=# begin;
BEGIN
alvherre=# declare c cursor for select 1 union all select 2;
DECLARE CURSOR
alvherre=# savepoint x;
SAVEPOINT
alvherre=# fetch from c;
?column?
----------
1
(1 fila)
alvherre=# rollback to x;
ROLLBACK
alvherre=# fetch from c;
?column?
----------
2
(1 fila)
alvherre=# commit;
COMMIT
--
Alvaro Herrera (<[EMAIL PROTECTED]>)
"The ability to monopolize a planet is insignificant
next to the power of the source"
Index: 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
*** portalmem.c 31 Dec 2004 22:02:48 -0000 1.76
--- portalmem.c 25 Jan 2005 17:52:52 -0000
***************
*** 623,663 ****
continue;
/*
! * Force any active portals of my own transaction into FAILED
* state. This is mostly to ensure that a portal running a FETCH
* 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;
}
}
}
--- 623,650 ----
continue;
/*
! * Force any active and ready portals of my own transaction
into FAILED
* state. This is mostly to ensure that a portal running a FETCH
* 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_READY)
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 7: don't forget to increase your free space map settings