From 37f49d35a25f41ede6404c02af21aaa7e7a7de3d Mon Sep 17 00:00:00 2001
From: amitlan <amitlangote09@gmail.com>
Date: Mon, 19 Oct 2020 17:17:33 +0900
Subject: [PATCH v13 1/3] Set ForeignScanState.resultRelInfo lazily

Instead of doing it in ExecInitForeignScan(), do it on the first
ForeignNext() call.  This also moves the BeginDirectModify() call
into ForeignNext().

This is in preparation of a later commit to make ModifyTable node
initialize ResultRelInfos lazily, that is as it begins executing,
instead of in ExecInitModifyTable().
---
 doc/src/sgml/fdwhandler.sgml           |  7 +++--
 src/backend/executor/nodeForeignscan.c | 39 ++++++++++++++++++--------
 2 files changed, 32 insertions(+), 14 deletions(-)

diff --git a/doc/src/sgml/fdwhandler.sgml b/doc/src/sgml/fdwhandler.sgml
index 854913ae5f..14d2d923de 100644
--- a/doc/src/sgml/fdwhandler.sgml
+++ b/doc/src/sgml/fdwhandler.sgml
@@ -967,9 +967,10 @@ BeginDirectModify(ForeignScanState *node,
 </programlisting>
 
      Prepare to execute a direct modification on the remote server.
-     This is called during executor startup.  It should perform any
-     initialization needed prior to the direct modification (that should be
-     done upon the first call to <function>IterateDirectModify</function>).
+     This is called right before the first time <function>IterateDirectModify</function>
+     is called on the node.  It should perform any initialization needed prior to the
+     direct modification (that should be done upon the first call to
+     <function>IterateDirectModify</function>).
      The <structname>ForeignScanState</structname> node has already been created, but
      its <structfield>fdw_state</structfield> field is still NULL.  Information about
      the table to modify is accessible through the
diff --git a/src/backend/executor/nodeForeignscan.c b/src/backend/executor/nodeForeignscan.c
index 0969e53c3a..25f6fd0e49 100644
--- a/src/backend/executor/nodeForeignscan.c
+++ b/src/backend/executor/nodeForeignscan.c
@@ -49,7 +49,31 @@ ForeignNext(ForeignScanState *node)
 	/* Call the Iterate function in short-lived context */
 	oldcontext = MemoryContextSwitchTo(econtext->ecxt_per_tuple_memory);
 	if (plan->operation != CMD_SELECT)
+	{
+		/*
+		 * For FDW's convenience, look up the result relation info and set
+		 * ForeignScanState.resultRelInfo if not already done.  This is also
+		 * a good time to call BeginDirectModify().
+		 */
+		Assert(plan->resultRelation > 0);
+		if (node->resultRelInfo == NULL)
+		{
+			EState   *estate = node->ss.ps.state;
+			ResultRelInfo *rInfo = estate->es_result_relations[plan->resultRelation - 1];
+
+			/* ExecInitModifyTable() must have initialized one already. */
+			Assert(rInfo != NULL);
+			node->resultRelInfo = rInfo;
+
+			oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
+			Assert(rInfo->ri_FdwRoutine != NULL &&
+				   rInfo->ri_FdwRoutine->BeginDirectModify != NULL);
+			rInfo->ri_FdwRoutine->BeginDirectModify(node,
+													estate->es_top_eflags);
+			MemoryContextSwitchTo(oldcontext);
+		}
 		slot = node->fdwroutine->IterateDirectModify(node);
+	}
 	else
 		slot = node->fdwroutine->IterateForeignScan(node);
 	MemoryContextSwitchTo(oldcontext);
@@ -215,24 +239,17 @@ ExecInitForeignScan(ForeignScan *node, EState *estate, int eflags)
 	scanstate->fdwroutine = fdwroutine;
 	scanstate->fdw_state = NULL;
 
-	/*
-	 * For the FDW's convenience, look up the modification target relation's.
-	 * ResultRelInfo.
-	 */
-	if (node->resultRelation > 0)
-		scanstate->resultRelInfo = estate->es_result_relations[node->resultRelation - 1];
-
 	/* Initialize any outer plan. */
 	if (outerPlan(node))
 		outerPlanState(scanstate) =
 			ExecInitNode(outerPlan(node), estate, eflags);
 
 	/*
-	 * Tell the FDW to initialize the scan.
+	 * Tell the FDW to initialize the scan.  For modify operations, any
+	 * additional initializations are performed right before calling
+	 * IterateDirectModify() for the first time.
 	 */
-	if (node->operation != CMD_SELECT)
-		fdwroutine->BeginDirectModify(scanstate, eflags);
-	else
+	if (node->operation == CMD_SELECT)
 		fdwroutine->BeginForeignScan(scanstate, eflags);
 
 	return scanstate;
-- 
2.24.1

