diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c index 9dc38d47ea..ad9edd26f1 100644 --- a/src/backend/executor/nodeForeignscan.c +++ b/src/backend/executor/nodeForeignscan.c @@ -44,12 +44,22 @@ ForeignNext(ForeignScanState *node) TupleTableSlot *slot; ForeignScan *plan = (ForeignScan *) node->ss.ps.plan; ExprContext *econtext = node->ss.ps.ps_ExprContext; + EState *estate = node->ss.ps.state; MemoryContext oldcontext; /* Call the Iterate function in short-lived context */ oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory); if (plan->operation != CMD_SELECT) + { + /* + * direct modifications cannot be re-evaluated, so shouldn't get here + * during EvalPlanQual processing + */ + if (estate->es_epq_active != NULL) + elog(ERROR, "cannot re-evaluate a Foreign Update or Delete during EvalPlanQual"); + slot = node->fdwroutine->IterateDirectModify(node); + } else slot = node->fdwroutine->IterateForeignScan(node); MemoryContextSwitchTo(oldcontext); @@ -223,11 +233,25 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags) scanstate->fdw_state = NULL; /* - * For the FDW's convenience, look up the modification target relation's. - * ResultRelInfo. + * For the FDW's convenience, look up the modification target relation's + * ResultRelInfo. The ModifyTable node should have initialized it for us, + * see ExecInitModifyTable. + * + * Don't try to look up the ResultRelInfo when EvalPlanQual is active, + * though. Direct modififications cannot be re-evaluated as part of + * EvalPlanQual. The lookup wouldn't work anyway because during + * EvalPlanQual processing, EvalPlanQual only initializes the subtree + * under the ModifyTable, and doesn't run ExecInitModifyTable. */ - if (node->resultRelation > 0) + if (node->resultRelation > 0 && estate->es_epq_active == NULL) + { + if (estate->es_result_relations == NULL || + estate->es_result_relations[node->resultRelation - 1] == NULL) + { + elog(ERROR, "result relation not initialized"); + } scanstate->resultRelInfo = estate->es_result_relations[node->resultRelation - 1]; + } /* Initialize any outer plan. */ if (outerPlan(node)) @@ -238,7 +262,15 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags) * Tell the FDW to initialize the scan. */ if (node->operation != CMD_SELECT) - fdwroutine->BeginDirectModify(scanstate, eflags); + { + /* + * Direct modifications cannot be re-evaluated by EvalPlanQual, so + * don't bother preparing the FDW. There can ForeignScan nodes in the + * EvalPlanQual subtree, but ExecForeignScan should never be called. + */ + if (estate->es_epq_active == NULL) + fdwroutine->BeginDirectModify(scanstate, eflags); + } else fdwroutine->BeginForeignScan(scanstate, eflags); @@ -255,10 +287,14 @@ void ExecEndForeignScan(ForeignScanState *node) { ForeignScan *plan = (ForeignScan *) node->ss.ps.plan; + EState *estate = node->ss.ps.state; /* Let the FDW shut down */ if (plan->operation != CMD_SELECT) - node->fdwroutine->EndDirectModify(node); + { + if (estate->es_epq_active == NULL) + node->fdwroutine->EndDirectModify(node); + } else node->fdwroutine->EndForeignScan(node);