From 8e6fa6f36ba2a2ffd1189d3c30ca10fb37333557 Mon Sep 17 00:00:00 2001 From: Etsuro Fujita Date: Tue, 1 Feb 2022 17:45:15 +0900 Subject: [PATCH] Further fix for EvalPlanQual with mix of local and foreign partitions. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We assume that direct-modify ForeignScan nodes cannot be re-evaluated during EvalPlanQual processing, but the rework for inherited UPDATE/DELETE in commit 86dc90056 changed things, without considering this, so that there can be such ForeignScan nodes in the EvalPlanQual subtree if the inheritance set contains foreign targets. Commit c3928b467 modified nodeForeignScan.c to avoid re-evaluating such ForeignScan nodes during EvalPlanQual processing, but the assumption made there that ExecForeignScan() should never be called for such ForeignScan nodes during EvalPlanQual processing was wrong in the case of an UPDATE/DELETE on a partitioned table with a foreign partition as the first child of it, leading to a segmentation fault or an “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. Per bug #17355 from Alexander Lakhin. Back-patch to v14 where both commits came in. Patch by me, tested by Alexander Lakhin. Discussion: https://postgr.es/m/17355-de8e362eb7001a96@postgresql.org --- src/backend/executor/nodeForeignscan.c | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c index c22d0e7651..cc5c180fb0 100644 --- a/src/backend/executor/nodeForeignscan.c +++ b/src/backend/executor/nodeForeignscan.c @@ -121,6 +121,15 @@ static TupleTableSlot * ExecForeignScan(PlanState *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, (ExecScanAccessMtd) ForeignNext, @@ -265,9 +274,11 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags) { /* * Direct modifications cannot be re-evaluated by EvalPlanQual, so - * don't bother preparing the FDW. There can be ForeignScan nodes in - * the EvalPlanQual subtree, but ExecForeignScan should never be - * called on them when EvalPlanQual is active. + * don't bother preparing the FDW. In case of an inherited + * UPDATE/DELETE with foreign targets there can be direct-modify + * ForeignScan nodes in the EvalPlanQual subtree, however, so we need + * to ignore such ForeignScan nodes during EvalPlanQual processing. + * See ExecForeignScan/ExecReScanForeignScan. */ if (estate->es_epq_active == NULL) fdwroutine->BeginDirectModify(scanstate, eflags); @@ -321,8 +332,17 @@ ExecEndForeignScan(ForeignScanState *node) void ExecReScanForeignScan(ForeignScanState *node) { + ForeignScan *plan = (ForeignScan *) node->ss.ps.plan; + EState *estate = node->ss.ps.state; 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); /* -- 2.14.3 (Apple Git-98)