Skip to content

Commit d8d93bc

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 04118de commit d8d93bc

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

395407
/*
@@ -404,7 +416,7 @@ PersistHoldablePortal(Portal portal)
404416
true);
405417

406418
/* Fetch the result set into the tuplestore */
407-
ExecutorRun(queryDesc, ForwardScanDirection, 0L, false);
419+
ExecutorRun(queryDesc, direction, 0L, false);
408420

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

0 commit comments

Comments
 (0)