mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-10-02 16:41:16 +02:00
Further fix for EvalPlanQual with mix of local and foreign partitions.
We assume that direct-modify ForeignScan nodes cannot be re-evaluated during EvalPlanQual processing, but the rework for inherited UPDATE/DELETE in commit86dc90056
changed things, without considering that, so that such ForeignScan nodes get called as part of the EvalPlanQual subtree during EvalPlanQual processing in the case of an inherited UPDATE/DELETE where the inheritance set contains foreign target relations. To avoid re-evaluating such ForeignScan nodes during EvalPlanQual processing, commitc3928b467
modified nodeForeignscan.c, but the assumption made there that ExecForeignScan() should never be called for such ForeignScan nodes during EvalPlanQual processing turned out to be wrong in some cases, leading to a segmentation fault or a "cannot re-evaluate a Foreign Update or Delete during EvalPlanQual" error. Fix by modifying nodeForeignscan.c further to avoid re-evaluating such ForeignScan nodes even in ExecForeignScan()/ExecReScanForeignScan() during EvalPlanQual processing. Since this makes non-reachable the test-and-elog added to ForeignNext() by commitc3928b467
that produced the aforesaid error, convert the test-and-elog to an Assert. Per bug #17355 from Alexander Lakhin. Back-patch to v14 where both commits came in. Patch by me, reviewed and tested by Alexander Lakhin and Amit Langote. Discussion: https://postgr.es/m/17355-de8e362eb7001a96@postgresql.org
This commit is contained in:
parent
2556076128
commit
7b0cec2fa0
@ -55,8 +55,7 @@ ForeignNext(ForeignScanState *node)
|
|||||||
* direct modifications cannot be re-evaluated, so shouldn't get here
|
* direct modifications cannot be re-evaluated, so shouldn't get here
|
||||||
* during EvalPlanQual processing
|
* during EvalPlanQual processing
|
||||||
*/
|
*/
|
||||||
if (estate->es_epq_active != NULL)
|
Assert(estate->es_epq_active == NULL);
|
||||||
elog(ERROR, "cannot re-evaluate a Foreign Update or Delete during EvalPlanQual");
|
|
||||||
|
|
||||||
slot = node->fdwroutine->IterateDirectModify(node);
|
slot = node->fdwroutine->IterateDirectModify(node);
|
||||||
}
|
}
|
||||||
@ -121,6 +120,15 @@ static TupleTableSlot *
|
|||||||
ExecForeignScan(PlanState *pstate)
|
ExecForeignScan(PlanState *pstate)
|
||||||
{
|
{
|
||||||
ForeignScanState *node = castNode(ForeignScanState, pstate);
|
ForeignScanState *node = castNode(ForeignScanState, pstate);
|
||||||
|
ForeignScan *plan = (ForeignScan *) node->ss.ps.plan;
|
||||||
|
EState *estate = node->ss.ps.state;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ignore direct modifications when EvalPlanQual is active --- they are
|
||||||
|
* irrelevant for EvalPlanQual rechecking
|
||||||
|
*/
|
||||||
|
if (estate->es_epq_active != NULL && plan->operation != CMD_SELECT)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
return ExecScan(&node->ss,
|
return ExecScan(&node->ss,
|
||||||
(ExecScanAccessMtd) ForeignNext,
|
(ExecScanAccessMtd) ForeignNext,
|
||||||
@ -265,9 +273,12 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Direct modifications cannot be re-evaluated by EvalPlanQual, so
|
* Direct modifications cannot be re-evaluated by EvalPlanQual, so
|
||||||
* don't bother preparing the FDW. There can be ForeignScan nodes in
|
* don't bother preparing the FDW.
|
||||||
* the EvalPlanQual subtree, but ExecForeignScan should never be
|
*
|
||||||
* called on them when EvalPlanQual is active.
|
* In case of an inherited UPDATE/DELETE with foreign targets there
|
||||||
|
* can be direct-modify ForeignScan nodes in the EvalPlanQual subtree,
|
||||||
|
* so we need to ignore such ForeignScan nodes during EvalPlanQual
|
||||||
|
* processing. See also ExecForeignScan/ExecReScanForeignScan.
|
||||||
*/
|
*/
|
||||||
if (estate->es_epq_active == NULL)
|
if (estate->es_epq_active == NULL)
|
||||||
fdwroutine->BeginDirectModify(scanstate, eflags);
|
fdwroutine->BeginDirectModify(scanstate, eflags);
|
||||||
@ -321,8 +332,17 @@ ExecEndForeignScan(ForeignScanState *node)
|
|||||||
void
|
void
|
||||||
ExecReScanForeignScan(ForeignScanState *node)
|
ExecReScanForeignScan(ForeignScanState *node)
|
||||||
{
|
{
|
||||||
|
ForeignScan *plan = (ForeignScan *) node->ss.ps.plan;
|
||||||
|
EState *estate = node->ss.ps.state;
|
||||||
PlanState *outerPlan = outerPlanState(node);
|
PlanState *outerPlan = outerPlanState(node);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Ignore direct modifications when EvalPlanQual is active --- they are
|
||||||
|
* irrelevant for EvalPlanQual rechecking
|
||||||
|
*/
|
||||||
|
if (estate->es_epq_active != NULL && plan->operation != CMD_SELECT)
|
||||||
|
return;
|
||||||
|
|
||||||
node->fdwroutine->ReScanForeignScan(node);
|
node->fdwroutine->ReScanForeignScan(node);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
Loading…
Reference in New Issue
Block a user