postgres.git / summary / log / commit / refs

commit    4228bde2e0b51e680c4dcfee21e95c7c6b9b3a3a
Author:   Tom Lane <tgl@sss.pgh.pa.us>
Date:     Thu Jun 13 17:11:45 2013 +0000
First released in: 9.3.0, 8.4.18, 9.0.14, 9.1.10, 9.2.5

    Only install a portal's ResourceOwner if it actually has one.
    
    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 | 6 ++++-- src/backend/tcop/pquery.c | 9 ++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c index abe445358de..f1aace2d2a3 100644 --- a/src/backend/commands/portalcmds.c +++ b/src/backend/commands/portalcmds.c @@ -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); diff --git a/src/backend/tcop/pquery.c b/src/backend/tcop/pquery.c index d60dc49c3c3..d36458d63f9 100644 --- a/src/backend/tcop/pquery.c +++ b/src/backend/tcop/pquery.c @@ -481,7 +481,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)); @@ -771,7 +772,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); @@ -1380,7 +1382,8 @@ PortalRunFetch(Portal portal, PG_TRY(); { ActivePortal = portal; - CurrentResourceOwner = portal->resowner; + if (portal->resowner) + CurrentResourceOwner = portal->resowner; PortalContext = PortalGetHeapMemory(portal); oldContext = MemoryContextSwitchTo(PortalContext); [parent: 6803921b545b]