Skip to content

Commit b7056c0

Browse files
committed
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 ba2c6d6 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
1 parent b27d0cd commit b7056c0

File tree

1 file changed

+15
-3
lines changed

1 file changed

+15
-3
lines changed

src/backend/commands/portalcmds.c

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -358,6 +358,8 @@ PersistHoldablePortal(Portal portal)
358358
savePortalContext = PortalContext;
359359
PG_TRY();
360360
{
361+
ScanDirection direction = ForwardScanDirection;
362+
361363
ActivePortal = portal;
362364
if (portal->resowner)
363365
CurrentResourceOwner = portal->resowner;
@@ -380,10 +382,20 @@ PersistHoldablePortal(Portal portal)
380382
}
381383
else
382384
{
383-
/* We must reset the cursor state as though at start of query */
385+
/* Disallow moving backwards from here */
384386
portal->atStart = true;
385-
portal->atEnd = false;
386387
portal->portalPos = 0;
388+
389+
/*
390+
* If we already reached end-of-query, set the direction to
391+
* NoMovement to avoid trying to fetch any tuples. (This check
392+
* exists because not all plan node types are robust about being
393+
* called again if they've already returned NULL once.) We'll
394+
* still set up an empty tuplestore, though, to keep this from
395+
* being a special case later.
396+
*/
397+
if (portal->atEnd)
398+
direction = NoMovementScanDirection;
387399
}
388400

389401
/*
@@ -400,7 +412,7 @@ PersistHoldablePortal(Portal portal)
400412
NULL);
401413

402414
/* Fetch the result set into the tuplestore */
403-
ExecutorRun(queryDesc, ForwardScanDirection, 0L, false);
415+
ExecutorRun(queryDesc, direction, 0L, false);
404416

405417
queryDesc->dest->rDestroy(queryDesc->dest);
406418
queryDesc->dest = NULL;

0 commit comments

Comments
 (0)