Skip to content

Commit 3cf3a65

Browse files
committed
Set scan direction appropriately for SubPlans (bug #15336)
When executing a SubPlan in an expression, the EState's direction field was left alone, resulting in an attempt to execute the subplan backwards if it was encountered during a backwards scan of a cursor. Also, though much less likely, it was possible to reach the execution of an InitPlan while in backwards-scan state. Repair by saving/restoring estate->es_direction and forcing forward scan mode in the relevant places. Backpatch all the way, since this has been broken since 8.3 (prior to commit c7ff766, SubPlans had their own EStates rather than sharing the parent plan's, so there was no confusion over scan direction). Per bug #15336 reported by Vladimir Baranoff; analysis and patch by me, review by Tom Lane. Discussion: https://postgr.es/m/153449812167.1304.1741624125628126322@wrigleys.postgresql.org
1 parent e626b6b commit 3cf3a65

File tree

3 files changed

+57
-2
lines changed

3 files changed

+57
-2
lines changed

src/backend/executor/nodeSubplan.c

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,9 @@ ExecSubPlan(SubPlanState *node,
6363
ExprDoneCond *isDone)
6464
{
6565
SubPlan *subplan = (SubPlan *) node->xprstate.expr;
66+
EState *estate = node->planstate->state;
67+
ScanDirection dir = estate->es_direction;
68+
Datum retval;
6669

6770
/* Set default values for result flags: non-null, not a set result */
6871
*isNull = false;
@@ -75,11 +78,19 @@ ExecSubPlan(SubPlanState *node,
7578
if (subplan->setParam != NIL)
7679
elog(ERROR, "cannot set parent params from subquery");
7780

81+
/* Force forward-scan mode for evaluation */
82+
estate->es_direction = ForwardScanDirection;
83+
7884
/* Select appropriate evaluation strategy */
7985
if (subplan->useHashTable)
80-
return ExecHashSubPlan(node, econtext, isNull);
86+
retval = ExecHashSubPlan(node, econtext, isNull);
8187
else
82-
return ExecScanSubPlan(node, econtext, isNull);
88+
retval = ExecScanSubPlan(node, econtext, isNull);
89+
90+
/* restore scan direction */
91+
estate->es_direction = dir;
92+
93+
return retval;
8394
}
8495

8596
/*
@@ -906,6 +917,8 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
906917
SubPlan *subplan = (SubPlan *) node->xprstate.expr;
907918
PlanState *planstate = node->planstate;
908919
SubLinkType subLinkType = subplan->subLinkType;
920+
EState *estate = planstate->state;
921+
ScanDirection dir = estate->es_direction;
909922
MemoryContext oldcontext;
910923
TupleTableSlot *slot;
911924
ListCell *l;
@@ -918,6 +931,12 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
918931
if (subLinkType == CTE_SUBLINK)
919932
elog(ERROR, "CTE subplans should not be executed via ExecSetParamPlan");
920933

934+
/*
935+
* Enforce forward scan direction regardless of caller. It's hard but not
936+
* impossible to get here in backward scan, so make it work anyway.
937+
*/
938+
estate->es_direction = ForwardScanDirection;
939+
921940
/*
922941
* Must switch to per-query memory context.
923942
*/
@@ -1048,6 +1067,9 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
10481067
}
10491068

10501069
MemoryContextSwitchTo(oldcontext);
1070+
1071+
/* restore scan direction */
1072+
estate->es_direction = dir;
10511073
}
10521074

10531075
/*

src/test/regress/expected/subselect.out

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -851,3 +851,20 @@ select nextval('ts1');
851851
11
852852
(1 row)
853853

854+
--
855+
-- Ensure that backward scan direction isn't propagated into
856+
-- expression subqueries (bug #15336)
857+
--
858+
begin;
859+
declare c1 scroll cursor for
860+
select * from generate_series(1,4) i
861+
where i <> all (values (2),(3));
862+
move forward all in c1;
863+
fetch backward all in c1;
864+
i
865+
---
866+
4
867+
1
868+
(2 rows)
869+
870+
commit;

src/test/regress/sql/subselect.sql

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -464,3 +464,19 @@ select * from
464464
order by 1;
465465

466466
select nextval('ts1');
467+
468+
--
469+
-- Ensure that backward scan direction isn't propagated into
470+
-- expression subqueries (bug #15336)
471+
--
472+
473+
begin;
474+
475+
declare c1 scroll cursor for
476+
select * from generate_series(1,4) i
477+
where i <> all (values (2),(3));
478+
479+
move forward all in c1;
480+
fetch backward all in c1;
481+
482+
commit;

0 commit comments

Comments
 (0)