Commit b7056c0a authored by Tom Lane's avatar Tom Lane

Avoid fetching from an already-terminated plan.

Some plan node types don't react well to being called again after
they've already returned NULL.  PortalRunSelect() has long dealt
with this by calling the executor with NoMovementScanDirection
if it sees that we've already run the portal to the end.  However,
commit ba2c6d6c overlooked this point, so that persisting an
already-fully-fetched cursor would fail if it had such a plan.

Per report from Tomas Barton.  Back-patch to v11, as the faulty
commit was.  (I've omitted a test case because the type of plan
that causes a problem isn't all that stable.)

Discussion: https://postgr.es/m/CAPV2KRjd=ErgVGbvO2Ty20tKTEZZr6cYsYLxgN_W3eAo9pf5sw@mail.gmail.com
parent b27d0cd3
...@@ -358,6 +358,8 @@ PersistHoldablePortal(Portal portal) ...@@ -358,6 +358,8 @@ PersistHoldablePortal(Portal portal)
savePortalContext = PortalContext; savePortalContext = PortalContext;
PG_TRY(); PG_TRY();
{ {
ScanDirection direction = ForwardScanDirection;
ActivePortal = portal; ActivePortal = portal;
if (portal->resowner) if (portal->resowner)
CurrentResourceOwner = portal->resowner; CurrentResourceOwner = portal->resowner;
...@@ -380,10 +382,20 @@ PersistHoldablePortal(Portal portal) ...@@ -380,10 +382,20 @@ PersistHoldablePortal(Portal portal)
} }
else else
{ {
/* We must reset the cursor state as though at start of query */ /* Disallow moving backwards from here */
portal->atStart = true; portal->atStart = true;
portal->atEnd = false;
portal->portalPos = 0; portal->portalPos = 0;
/*
* If we already reached end-of-query, set the direction to
* NoMovement to avoid trying to fetch any tuples. (This check
* exists because not all plan node types are robust about being
* called again if they've already returned NULL once.) We'll
* still set up an empty tuplestore, though, to keep this from
* being a special case later.
*/
if (portal->atEnd)
direction = NoMovementScanDirection;
} }
/* /*
...@@ -400,7 +412,7 @@ PersistHoldablePortal(Portal portal) ...@@ -400,7 +412,7 @@ PersistHoldablePortal(Portal portal)
NULL); NULL);
/* Fetch the result set into the tuplestore */ /* Fetch the result set into the tuplestore */
ExecutorRun(queryDesc, ForwardScanDirection, 0L, false); ExecutorRun(queryDesc, direction, 0L, false);
queryDesc->dest->rDestroy(queryDesc->dest); queryDesc->dest->rDestroy(queryDesc->dest);
queryDesc->dest = NULL; queryDesc->dest = NULL;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment