aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/execMain.c1
-rw-r--r--src/backend/executor/nodeForeignscan.c17
-rw-r--r--src/backend/executor/nodeModifyTable.c60
3 files changed, 65 insertions, 13 deletions
diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c
index 687256279ab..ac0230411c3 100644
--- a/src/backend/executor/execMain.c
+++ b/src/backend/executor/execMain.c
@@ -1245,6 +1245,7 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo,
else
resultRelInfo->ri_FdwRoutine = NULL;
resultRelInfo->ri_FdwState = NULL;
+ resultRelInfo->ri_usesFdwDirectModify = false;
resultRelInfo->ri_ConstraintExprs = NULL;
resultRelInfo->ri_junkFilter = NULL;
resultRelInfo->ri_projectReturning = NULL;
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index 388c9227498..300f947d431 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -48,7 +48,10 @@ ForeignNext(ForeignScanState *node)
/* Call the Iterate function in short-lived context */
oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
- slot = node->fdwroutine->IterateForeignScan(node);
+ if (plan->operation != CMD_SELECT)
+ slot = node->fdwroutine->IterateDirectModify(node);
+ else
+ slot = node->fdwroutine->IterateForeignScan(node);
MemoryContextSwitchTo(oldcontext);
/*
@@ -226,7 +229,10 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
/*
* Tell the FDW to initialize the scan.
*/
- fdwroutine->BeginForeignScan(scanstate, eflags);
+ if (node->operation != CMD_SELECT)
+ fdwroutine->BeginDirectModify(scanstate, eflags);
+ else
+ fdwroutine->BeginForeignScan(scanstate, eflags);
return scanstate;
}
@@ -240,8 +246,13 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
void
ExecEndForeignScan(ForeignScanState *node)
{
+ ForeignScan *plan = (ForeignScan *) node->ss.ps.plan;
+
/* Let the FDW shut down */
- node->fdwroutine->EndForeignScan(node);
+ if (plan->operation != CMD_SELECT)
+ node->fdwroutine->EndDirectModify(node);
+ else
+ node->fdwroutine->EndForeignScan(node);
/* Shut down any outer plan. */
if (outerPlanState(node))
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 27051e80b08..e62c8aad657 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -138,13 +138,17 @@ ExecCheckPlanOutput(Relation resultRel, List *targetList)
* tupleSlot: slot holding tuple actually inserted/updated/deleted
* planSlot: slot holding tuple returned by top subplan node
*
+ * Note: If tupleSlot is NULL, the FDW should have already provided econtext's
+ * scan tuple.
+ *
* Returns a slot holding the result tuple
*/
static TupleTableSlot *
-ExecProcessReturning(ProjectionInfo *projectReturning,
+ExecProcessReturning(ResultRelInfo *resultRelInfo,
TupleTableSlot *tupleSlot,
TupleTableSlot *planSlot)
{
+ ProjectionInfo *projectReturning = resultRelInfo->ri_projectReturning;
ExprContext *econtext = projectReturning->pi_exprContext;
/*
@@ -154,7 +158,20 @@ ExecProcessReturning(ProjectionInfo *projectReturning,
ResetExprContext(econtext);
/* Make tuple and any needed join variables available to ExecProject */
- econtext->ecxt_scantuple = tupleSlot;
+ if (tupleSlot)
+ econtext->ecxt_scantuple = tupleSlot;
+ else
+ {
+ HeapTuple tuple;
+
+ /*
+ * RETURNING expressions might reference the tableoid column, so
+ * initialize t_tableOid before evaluating them.
+ */
+ Assert(!TupIsNull(econtext->ecxt_scantuple));
+ tuple = ExecMaterializeSlot(econtext->ecxt_scantuple);
+ tuple->t_tableOid = RelationGetRelid(resultRelInfo->ri_RelationDesc);
+ }
econtext->ecxt_outertuple = planSlot;
/* Compute the RETURNING expressions */
@@ -496,8 +513,7 @@ ExecInsert(ModifyTableState *mtstate,
/* Process RETURNING if present */
if (resultRelInfo->ri_projectReturning)
- return ExecProcessReturning(resultRelInfo->ri_projectReturning,
- slot, planSlot);
+ return ExecProcessReturning(resultRelInfo, slot, planSlot);
return NULL;
}
@@ -738,8 +754,7 @@ ldelete:;
ExecStoreTuple(&deltuple, slot, InvalidBuffer, false);
}
- rslot = ExecProcessReturning(resultRelInfo->ri_projectReturning,
- slot, planSlot);
+ rslot = ExecProcessReturning(resultRelInfo, slot, planSlot);
/*
* Before releasing the target tuple again, make sure rslot has a
@@ -1024,8 +1039,7 @@ lreplace:;
/* Process RETURNING if present */
if (resultRelInfo->ri_projectReturning)
- return ExecProcessReturning(resultRelInfo->ri_projectReturning,
- slot, planSlot);
+ return ExecProcessReturning(resultRelInfo, slot, planSlot);
return NULL;
}
@@ -1380,6 +1394,26 @@ ExecModifyTable(ModifyTableState *node)
break;
}
+ /*
+ * If resultRelInfo->ri_usesFdwDirectModify is true, all we need to do
+ * here is compute the RETURNING expressions.
+ */
+ if (resultRelInfo->ri_usesFdwDirectModify)
+ {
+ Assert(resultRelInfo->ri_projectReturning);
+
+ /*
+ * A scan slot containing the data that was actually inserted,
+ * updated or deleted has already been made available to
+ * ExecProcessReturning by IterateDirectModify, so no need to
+ * provide it here.
+ */
+ slot = ExecProcessReturning(resultRelInfo, NULL, planSlot);
+
+ estate->es_result_relation_info = saved_resultRelInfo;
+ return slot;
+ }
+
EvalPlanQualSetSlot(&node->mt_epqstate, planSlot);
slot = planSlot;
@@ -1559,6 +1593,10 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
{
subplan = (Plan *) lfirst(l);
+ /* Initialize the usesFdwDirectModify flag */
+ resultRelInfo->ri_usesFdwDirectModify = bms_is_member(i,
+ node->fdwDirectModifyPlans);
+
/*
* Verify result relation is a valid target for the current operation
*/
@@ -1583,7 +1621,8 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags)
mtstate->mt_plans[i] = ExecInitNode(subplan, estate, eflags);
/* Also let FDWs init themselves for foreign-table result rels */
- if (resultRelInfo->ri_FdwRoutine != NULL &&
+ if (!resultRelInfo->ri_usesFdwDirectModify &&
+ resultRelInfo->ri_FdwRoutine != NULL &&
resultRelInfo->ri_FdwRoutine->BeginForeignModify != NULL)
{
List *fdw_private = (List *) list_nth(node->fdwPrivLists, i);
@@ -1910,7 +1949,8 @@ ExecEndModifyTable(ModifyTableState *node)
{
ResultRelInfo *resultRelInfo = node->resultRelInfo + i;
- if (resultRelInfo->ri_FdwRoutine != NULL &&
+ if (!resultRelInfo->ri_usesFdwDirectModify &&
+ resultRelInfo->ri_FdwRoutine != NULL &&
resultRelInfo->ri_FdwRoutine->EndForeignModify != NULL)
resultRelInfo->ri_FdwRoutine->EndForeignModify(node->ps.state,
resultRelInfo);