Skip to content

Commit d31ebbf

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 bd30f51 commit d31ebbf

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
@@ -65,6 +65,9 @@ ExecSubPlan(SubPlanState *node,
6565
bool *isNull)
6666
{
6767
SubPlan *subplan = node->subplan;
68+
EState *estate = node->planstate->state;
69+
ScanDirection dir = estate->es_direction;
70+
Datum retval;
6871

6972
CHECK_FOR_INTERRUPTS();
7073

@@ -77,11 +80,19 @@ ExecSubPlan(SubPlanState *node,
7780
if (subplan->setParam != NIL && subplan->subLinkType != MULTIEXPR_SUBLINK)
7881
elog(ERROR, "cannot set parent params from subquery");
7982

83+
/* Force forward-scan mode for evaluation */
84+
estate->es_direction = ForwardScanDirection;
85+
8086
/* Select appropriate evaluation strategy */
8187
if (subplan->useHashTable)
82-
return ExecHashSubPlan(node, econtext, isNull);
88+
retval = ExecHashSubPlan(node, econtext, isNull);
8389
else
84-
return ExecScanSubPlan(node, econtext, isNull);
90+
retval = ExecScanSubPlan(node, econtext, isNull);
91+
92+
/* restore scan direction */
93+
estate->es_direction = dir;
94+
95+
return retval;
8596
}
8697

8798
/*
@@ -918,6 +929,8 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
918929
SubPlan *subplan = node->subplan;
919930
PlanState *planstate = node->planstate;
920931
SubLinkType subLinkType = subplan->subLinkType;
932+
EState *estate = planstate->state;
933+
ScanDirection dir = estate->es_direction;
921934
MemoryContext oldcontext;
922935
TupleTableSlot *slot;
923936
ListCell *pvar;
@@ -931,6 +944,12 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
931944
if (subLinkType == CTE_SUBLINK)
932945
elog(ERROR, "CTE subplans should not be executed via ExecSetParamPlan");
933946

947+
/*
948+
* Enforce forward scan direction regardless of caller. It's hard but not
949+
* impossible to get here in backward scan, so make it work anyway.
950+
*/
951+
estate->es_direction = ForwardScanDirection;
952+
934953
/* Initialize ArrayBuildStateAny in caller's context, if needed */
935954
if (subLinkType == ARRAY_SUBLINK)
936955
astate = initArrayResultAny(subplan->firstColType,
@@ -1083,6 +1102,9 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
10831102
}
10841103

10851104
MemoryContextSwitchTo(oldcontext);
1105+
1106+
/* restore scan direction */
1107+
estate->es_direction = dir;
10861108
}
10871109

10881110
/*

src/test/regress/expected/subselect.out

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1085,3 +1085,20 @@ NOTICE: x = 9, y = 13
10851085
(3 rows)
10861086

10871087
drop function tattle(x int, y int);
1088+
--
1089+
-- Ensure that backward scan direction isn't propagated into
1090+
-- expression subqueries (bug #15336)
1091+
--
1092+
begin;
1093+
declare c1 scroll cursor for
1094+
select * from generate_series(1,4) i
1095+
where i <> all (values (2),(3));
1096+
move forward all in c1;
1097+
fetch backward all in c1;
1098+
i
1099+
---
1100+
4
1101+
1
1102+
(2 rows)
1103+
1104+
commit;

src/test/regress/sql/subselect.sql

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,3 +568,19 @@ select * from
568568
where tattle(x, u);
569569

570570
drop function tattle(x int, y int);
571+
572+
--
573+
-- Ensure that backward scan direction isn't propagated into
574+
-- expression subqueries (bug #15336)
575+
--
576+
577+
begin;
578+
579+
declare c1 scroll cursor for
580+
select * from generate_series(1,4) i
581+
where i <> all (values (2),(3));
582+
583+
move forward all in c1;
584+
fetch backward all in c1;
585+
586+
commit;

0 commit comments

Comments
 (0)