1
0
mirror of https://github.com/postgres/postgres.git synced 2025-06-13 07:41:39 +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:
Andrew Gierth
2018-08-17 15:04:26 +01:00
parent 9bed827b18
commit 520acab171
3 changed files with 57 additions and 2 deletions

View File

@ -65,6 +65,9 @@ ExecSubPlan(SubPlanState *node,
bool *isNull)
{
SubPlan *subplan = node->subplan;
EState *estate = node->planstate->state;
ScanDirection dir = estate->es_direction;
Datum retval;
CHECK_FOR_INTERRUPTS();
@ -77,11 +80,19 @@ ExecSubPlan(SubPlanState *node,
if (subplan->setParam != NIL && subplan->subLinkType != MULTIEXPR_SUBLINK)
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;
}
/*
@ -1006,6 +1017,8 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
SubPlan *subplan = node->subplan;
PlanState *planstate = node->planstate;
SubLinkType subLinkType = subplan->subLinkType;
EState *estate = planstate->state;
ScanDirection dir = estate->es_direction;
MemoryContext oldcontext;
TupleTableSlot *slot;
ListCell *pvar;
@ -1019,6 +1032,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;
/* Initialize ArrayBuildStateAny in caller's context, if needed */
if (subLinkType == ARRAY_SUBLINK)
astate = initArrayResultAny(subplan->firstColType,
@ -1171,6 +1190,9 @@ ExecSetParamPlan(SubPlanState *node, ExprContext *econtext)
}
MemoryContextSwitchTo(oldcontext);
/* restore scan direction */
estate->es_direction = dir;
}
/*