mirror of
https://github.com/postgres/postgres.git
synced 2025-06-11 20:28:21 +03:00
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 c7ff7663e
, 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
This commit is contained in:
@ -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;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
Reference in New Issue
Block a user