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)
|
ExprDoneCond *isDone)
|
||||||
{
|
{
|
||||||
SubPlan *subplan = (SubPlan *) node->xprstate.expr;
|
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 */
|
/* Set default values for result flags: non-null, not a set result */
|
||||||
*isNull = false;
|
*isNull = false;
|
||||||
@ -75,11 +78,19 @@ ExecSubPlan(SubPlanState *node,
|
|||||||
if (subplan->setParam != NIL)
|
if (subplan->setParam != NIL)
|
||||||
elog(ERROR, "cannot set parent params from subquery");
|
elog(ERROR, "cannot set parent params from subquery");
|
||||||
|
|
||||||
|
/* Force forward-scan mode for evaluation */
|
||||||
|
estate->es_direction = ForwardScanDirection;
|
||||||
|
|
||||||
/* Select appropriate evaluation strategy */
|
/* Select appropriate evaluation strategy */
|
||||||
if (subplan->useHashTable)
|
if (subplan->useHashTable)
|
||||||
return ExecHashSubPlan(node, econtext, isNull);
|
retval = ExecHashSubPlan(node, econtext, isNull);
|
||||||
else
|
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;
|
SubPlan *subplan = (SubPlan *) node->xprstate.expr;
|
||||||
PlanState *planstate = node->planstate;
|
PlanState *planstate = node->planstate;
|
||||||
SubLinkType subLinkType = subplan->subLinkType;
|
SubLinkType subLinkType = subplan->subLinkType;
|
||||||
|
EState *estate = planstate->state;
|
||||||
|
ScanDirection dir = estate->es_direction;
|
||||||
MemoryContext oldcontext;
|
MemoryContext oldcontext;
|
||||||
TupleTableSlot *slot;
|
TupleTableSlot *slot;
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
@ -918,6 +931,12 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
|
|||||||
if (subLinkType == CTE_SUBLINK)
|
if (subLinkType == CTE_SUBLINK)
|
||||||
elog(ERROR, "CTE subplans should not be executed via ExecSetParamPlan");
|
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.
|
* Must switch to per-query memory context.
|
||||||
*/
|
*/
|
||||||
@ -1048,6 +1067,9 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
|
|||||||
}
|
}
|
||||||
|
|
||||||
MemoryContextSwitchTo(oldcontext);
|
MemoryContextSwitchTo(oldcontext);
|
||||||
|
|
||||||
|
/* restore scan direction */
|
||||||
|
estate->es_direction = dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -851,3 +851,20 @@ select nextval('ts1');
|
|||||||
11
|
11
|
||||||
(1 row)
|
(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;
|
order by 1;
|
||||||
|
|
||||||
select nextval('ts1');
|
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