diff --git a/src/backend/executor/nodeSubplan.c b/src/backend/executor/nodeSubplan.c index 5d02d9420b1..225b323f55e 100644 --- a/src/backend/executor/nodeSubplan.c +++ b/src/backend/executor/nodeSubplan.c @@ -63,6 +63,9 @@ ExecSubPlan(SubPlanState *node, ExprDoneCond *isDone) { SubPlan *subplan = (SubPlan *) node->xprstate.expr; + EState *estate = node->planstate->state; + ScanDirection dir = estate->es_direction; + Datum retval; /* Set default values for result flags: non-null, not a set result */ *isNull = false; @@ -75,11 +78,19 @@ ExecSubPlan(SubPlanState *node, if (subplan->setParam != NIL) elog(ERROR, "cannot set parent params from subquery"); + /* Force forward-scan mode for evaluation */ + estate->es_direction = ForwardScanDirection; + /* Select appropriate evaluation strategy */ if (subplan->useHashTable) - return ExecHashSubPlan(node, econtext, isNull); + retval = ExecHashSubPlan(node, econtext, isNull); else - return ExecScanSubPlan(node, econtext, isNull); + retval = ExecScanSubPlan(node, econtext, isNull); + + /* restore scan direction */ + estate->es_direction = dir; + + return retval; } /* @@ -906,6 +917,8 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext) SubPlan *subplan = (SubPlan *) node->xprstate.expr; PlanState *planstate = node->planstate; SubLinkType subLinkType = subplan->subLinkType; + EState *estate = planstate->state; + ScanDirection dir = estate->es_direction; MemoryContext oldcontext; TupleTableSlot *slot; ListCell *l; @@ -918,6 +931,12 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext) if (subLinkType == CTE_SUBLINK) elog(ERROR, "CTE subplans should not be executed via ExecSetParamPlan"); + /* + * Enforce forward scan direction regardless of caller. It's hard but not + * impossible to get here in backward scan, so make it work anyway. + */ + estate->es_direction = ForwardScanDirection; + /* * Must switch to per-query memory context. */ @@ -1048,6 +1067,9 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext) } MemoryContextSwitchTo(oldcontext); + + /* restore scan direction */ + estate->es_direction = dir; } /* diff --git a/src/test/regress/expected/subselect.out b/src/test/regress/expected/subselect.out index 7532c272a52..5bad96366b6 100644 --- a/src/test/regress/expected/subselect.out +++ b/src/test/regress/expected/subselect.out @@ -851,3 +851,20 @@ select nextval('ts1'); 11 (1 row) +-- +-- Ensure that backward scan direction isn't propagated into +-- expression subqueries (bug #15336) +-- +begin; +declare c1 scroll cursor for + select * from generate_series(1,4) i + where i <> all (values (2),(3)); +move forward all in c1; +fetch backward all in c1; + i +--- + 4 + 1 +(2 rows) + +commit; diff --git a/src/test/regress/sql/subselect.sql b/src/test/regress/sql/subselect.sql index 81cf79928b3..decfffd3e4b 100644 --- a/src/test/regress/sql/subselect.sql +++ b/src/test/regress/sql/subselect.sql @@ -464,3 +464,19 @@ select * from order by 1; select nextval('ts1'); + +-- +-- Ensure that backward scan direction isn't propagated into +-- expression subqueries (bug #15336) +-- + +begin; + +declare c1 scroll cursor for + select * from generate_series(1,4) i + where i <> all (values (2),(3)); + +move forward all in c1; +fetch backward all in c1; + +commit;