From af6856dd28b9705e402a198779491e1b2ef9a743 Mon Sep 17 00:00:00 2001 From: amitlan Date: Mon, 19 Oct 2020 17:17:33 +0900 Subject: [PATCH v11 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 9c92934..b1d7c84 100644 --- a/doc/src/sgml/fdwhandler.sgml +++ b/doc/src/sgml/fdwhandler.sgml @@ -890,9 +890,10 @@ BeginDirectModify(ForeignScanState *node, 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 IterateDirectModify). + This is called right before the first time IterateDirectModify + 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 + IterateDirectModify). The ForeignScanState node has already been created, but its fdw_state 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 0b20f94..5259abf 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; -- 1.8.3.1