Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Only install a portal's ResourceOwner if it actually has one.
authorTom Lane <tgl@sss.pgh.pa.us>
Thu, 13 Jun 2013 17:11:51 +0000 (13:11 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Thu, 13 Jun 2013 17:11:51 +0000 (13:11 -0400)
In most scenarios a portal without a ResourceOwner is dead and not subject
to any further execution, but a portal for a cursor WITH HOLD remains in
existence with no ResourceOwner after the creating transaction is over.
In this situation, if we attempt to "execute" the portal directly to fetch
data from it, we were setting CurrentResourceOwner to NULL, leading to a
segfault if the datatype output code did anything that required a resource
owner (such as trying to fetch system catalog entries that weren't already
cached).  The case appears to be impossible to provoke with stock libpq,
but psqlODBC at least is able to cause it when working with held cursors.

Simplest fix is to just skip the assignment to CurrentResourceOwner, so
that any resources used by the data output operations will be managed by
the transaction-level resource owner instead.  For consistency I changed
all the places that install a portal's resowner as current, even though
some of them are probably not reachable with a held cursor's portal.

Per report from Joshua Berry (with thanks to Hiroshi Inoue for developing
a self-contained test case).  Back-patch to all supported versions.

src/backend/commands/portalcmds.c
src/backend/tcop/pquery.c

index f1ae01908a944b0e15ee7d276e1186520de8e3b3..d6c1a580b7cfb0ad1758298fdf0a3a1a04081e7f 100644 (file)
@@ -263,7 +263,8 @@ PortalCleanup(Portal portal)
            saveResourceOwner = CurrentResourceOwner;
            PG_TRY();
            {
-               CurrentResourceOwner = portal->resowner;
+               if (portal->resowner)
+                   CurrentResourceOwner = portal->resowner;
                /* we do not need AfterTriggerEndQuery() here */
                ExecutorEnd(queryDesc);
                FreeQueryDesc(queryDesc);
@@ -338,7 +339,8 @@ PersistHoldablePortal(Portal portal)
    PG_TRY();
    {
        ActivePortal = portal;
-       CurrentResourceOwner = portal->resowner;
+       if (portal->resowner)
+           CurrentResourceOwner = portal->resowner;
        PortalContext = PortalGetHeapMemory(portal);
 
        MemoryContextSwitchTo(PortalContext);
index 98716830cd6f7f6583f23364da6a5afcca975dcf..9933f7de071d429e38fe7a71c1b14f834f09fd72 100644 (file)
@@ -479,7 +479,8 @@ PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot)
    PG_TRY();
    {
        ActivePortal = portal;
-       CurrentResourceOwner = portal->resowner;
+       if (portal->resowner)
+           CurrentResourceOwner = portal->resowner;
        PortalContext = PortalGetHeapMemory(portal);
 
        oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
@@ -768,7 +769,8 @@ PortalRun(Portal portal, long count, bool isTopLevel,
    PG_TRY();
    {
        ActivePortal = portal;
-       CurrentResourceOwner = portal->resowner;
+       if (portal->resowner)
+           CurrentResourceOwner = portal->resowner;
        PortalContext = PortalGetHeapMemory(portal);
 
        MemoryContextSwitchTo(PortalContext);
@@ -1375,7 +1377,8 @@ PortalRunFetch(Portal portal,
    PG_TRY();
    {
        ActivePortal = portal;
-       CurrentResourceOwner = portal->resowner;
+       if (portal->resowner)
+           CurrentResourceOwner = portal->resowner;
        PortalContext = PortalGetHeapMemory(portal);
 
        oldContext = MemoryContextSwitchTo(PortalContext);