Skip to content

Commit 2e75e96

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 a7a73ce commit 2e75e96

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
@@ -365,6 +365,8 @@ PersistHoldablePortal(Portal portal)
365365
savePortalContext = PortalContext;
366366
PG_TRY();
367367
{
368+
ScanDirection direction = ForwardScanDirection;
369+
368370
ActivePortal = portal;
369371
if (portal->resowner)
370372
CurrentResourceOwner = portal->resowner;
@@ -387,10 +389,20 @@ PersistHoldablePortal(Portal portal)
387389
}
388390
else
389391
{
390-
/* We must reset the cursor state as though at start of query */
392+
/* Disallow moving backwards from here */
391393
portal->atStart = true;
392-
portal->atEnd = false;
393394
portal->portalPos = 0;
395+
396+
/*
397+
* If we already reached end-of-query, set the direction to
398+
* NoMovement to avoid trying to fetch any tuples. (This check
399+
* exists because not all plan node types are robust about being
400+
* called again if they've already returned NULL once.) We'll
401+
* still set up an empty tuplestore, though, to keep this from
402+
* being a special case later.
403+
*/
404+
if (portal->atEnd)
405+
direction = NoMovementScanDirection;
394406
}
395407

396408
/*
@@ -405,7 +417,7 @@ PersistHoldablePortal(Portal portal)
405417
true);
406418

407419
/* Fetch the result set into the tuplestore */
408-
ExecutorRun(queryDesc, ForwardScanDirection, 0L, false);
420+
ExecutorRun(queryDesc, direction, 0L, false);
409421

410422
queryDesc->dest->rDestroy(queryDesc->dest);
411423
queryDesc->dest = NULL;

0 commit comments

Comments
 (0)