diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c index 033aeb2556..9982007082 100644 --- a/contrib/postgres_fdw/postgres_fdw.c +++ b/contrib/postgres_fdw/postgres_fdw.c @@ -197,6 +197,7 @@ typedef struct PgFdwModifyState typedef struct PgFdwDirectModifyState { Relation rel; /* relcache entry for the foreign table */ + ResultRelInfo *relInfo; /* ResultRelInfo for the foreign table */ AttInMetadata *attinmeta; /* attribute datatype conversion metadata */ /* extracted fdw_private data */ @@ -2303,6 +2304,7 @@ postgresPlanDirectModify(PlannerInfo *root, * Update the operation info. */ fscan->operation = operation; + fscan->resultRelation = resultRelation; /* * Update the fdw_exprs list that will be available to the executor. @@ -2368,7 +2370,7 @@ postgresBeginDirectModify(ForeignScanState *node, int eflags) * Identify which user to do the remote access as. This should match what * ExecCheckRTEPerms() does. */ - rtindex = estate->es_result_relation_info->ri_RangeTableIndex; + rtindex = fsplan->resultRelation; rte = exec_rt_fetch(rtindex, estate); userid = rte->checkAsUser ? rte->checkAsUser : GetUserId(); @@ -2380,6 +2382,9 @@ postgresBeginDirectModify(ForeignScanState *node, int eflags) table = GetForeignTable(RelationGetRelid(dmstate->rel)); user = GetUserMapping(userid, table->serverid); + /* Get ResultRelInfo for foreign table. */ + dmstate->relInfo = ExecFindResultRelInfo(estate, rtindex, false); + /* * Get connection to the foreign server. Connection manager will * establish new connection if necessary. @@ -2463,7 +2468,7 @@ postgresIterateDirectModify(ForeignScanState *node) { PgFdwDirectModifyState *dmstate = (PgFdwDirectModifyState *) node->fdw_state; EState *estate = node->ss.ps.state; - ResultRelInfo *resultRelInfo = estate->es_result_relation_info; + ResultRelInfo *resultRelInfo = dmstate->relInfo; /* * If this is the first call after Begin, execute the statement. @@ -4033,7 +4038,7 @@ get_returning_data(ForeignScanState *node) { PgFdwDirectModifyState *dmstate = (PgFdwDirectModifyState *) node->fdw_state; EState *estate = node->ss.ps.state; - ResultRelInfo *resultRelInfo = estate->es_result_relation_info; + ResultRelInfo *resultRelInfo = dmstate->relInfo; TupleTableSlot *slot = node->ss.ss_ScanTupleSlot; TupleTableSlot *resultSlot; @@ -4180,7 +4185,7 @@ apply_returning_filter(PgFdwDirectModifyState *dmstate, TupleTableSlot *slot, EState *estate) { - ResultRelInfo *relInfo = estate->es_result_relation_info; + ResultRelInfo *relInfo = dmstate->relInfo; TupleDesc resultTupType = RelationGetDescr(dmstate->resultRel); TupleTableSlot *resultSlot; Datum *values; diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index dbd7dd9bcd..4d0d0553be 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -1349,6 +1349,31 @@ InitResultRelInfo(ResultRelInfo *resultRelInfo, resultRelInfo->ri_CopyMultiInsertBuffer = NULL; } +/* + * ExecFindResultRelInfo -- find the ResultRelInfo struct for given rangetable + * index + * + * This function only searches through the query result relations. If no such + * struct, either return NULL or throw error depending on missing_ok + */ +ResultRelInfo * +ExecFindResultRelInfo(EState *estate, Index rti, bool missing_ok) +{ + ResultRelInfo *rInfo = estate->es_result_relations; + int nr = estate->es_num_result_relations; + + while (nr > 0) + { + if (rInfo->ri_RangeTableIndex == rti) + return rInfo; + rInfo++; + nr--; + } + if (!missing_ok) + elog(ERROR, "failed to find ResultRelInfo for rangetable index %u", rti); + return NULL; +} + /* * ExecGetTriggerResultRel * Get a ResultRelInfo for a trigger target relation. diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c index 6414aded0e..9342b99aae 100644 --- a/src/backend/nodes/copyfuncs.c +++ b/src/backend/nodes/copyfuncs.c @@ -751,6 +751,7 @@ _copyForeignScan(const ForeignScan *from) * copy remainder of node */ COPY_SCALAR_FIELD(operation); + COPY_SCALAR_FIELD(resultRelation); COPY_SCALAR_FIELD(fs_server); COPY_NODE_FIELD(fdw_exprs); COPY_NODE_FIELD(fdw_private); diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c index 86c31a48c9..4dadb9ff7c 100644 --- a/src/backend/nodes/outfuncs.c +++ b/src/backend/nodes/outfuncs.c @@ -688,6 +688,7 @@ _outForeignScan(StringInfo str, const ForeignScan *node) _outScanInfo(str, (const Scan *) node); WRITE_ENUM_FIELD(operation, CmdType); + WRITE_UINT_FIELD(resultRelation); WRITE_OID_FIELD(fs_server); WRITE_NODE_FIELD(fdw_exprs); WRITE_NODE_FIELD(fdw_private); diff --git a/src/backend/nodes/readfuncs.c b/src/backend/nodes/readfuncs.c index 6c2626ee62..04080c752a 100644 --- a/src/backend/nodes/readfuncs.c +++ b/src/backend/nodes/readfuncs.c @@ -1976,6 +1976,7 @@ _readForeignScan(void) ReadCommonScan(&local_node->scan); READ_ENUM_FIELD(operation, CmdType); + READ_UINT_FIELD(resultRelation); READ_OID_FIELD(fs_server); READ_NODE_FIELD(fdw_exprs); READ_NODE_FIELD(fdw_private); diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c index c6b8553a08..cc5be409ec 100644 --- a/src/backend/optimizer/plan/createplan.c +++ b/src/backend/optimizer/plan/createplan.c @@ -5415,6 +5415,7 @@ make_foreignscan(List *qptlist, plan->righttree = NULL; node->scan.scanrelid = scanrelid; node->operation = CMD_SELECT; + node->resultRelation = 0; /* fs_server will be filled in by create_foreignscan_plan */ node->fs_server = InvalidOid; node->fdw_exprs = fdw_exprs; diff --git a/src/backend/optimizer/plan/setrefs.c b/src/backend/optimizer/plan/setrefs.c index dc11f098e0..25c1e7dfc7 100644 --- a/src/backend/optimizer/plan/setrefs.c +++ b/src/backend/optimizer/plan/setrefs.c @@ -1158,6 +1158,10 @@ set_foreignscan_references(PlannerInfo *root, if (fscan->scan.scanrelid > 0) fscan->scan.scanrelid += rtoffset; + /* Adjust resultRelation if it's valid */ + if (fscan->resultRelation > 0) + fscan->resultRelation += rtoffset; + if (fscan->fdw_scan_tlist != NIL || fscan->scan.scanrelid == 0) { /* diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 1fb28b4596..a0533df779 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -184,6 +184,7 @@ extern void InitResultRelInfo(ResultRelInfo *resultRelInfo, Index resultRelationIndex, Relation partition_root, int instrument_options); +extern ResultRelInfo *ExecFindResultRelInfo(EState *estate, Index rti, bool missing_ok); extern ResultRelInfo *ExecGetTriggerResultRel(EState *estate, Oid relid); extern void ExecCleanUpTriggerState(EState *estate); extern void ExecConstraints(ResultRelInfo *resultRelInfo, diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h index 70f8b8e22b..218626254f 100644 --- a/src/include/nodes/plannodes.h +++ b/src/include/nodes/plannodes.h @@ -609,6 +609,8 @@ typedef struct ForeignScan { Scan scan; CmdType operation; /* SELECT/INSERT/UPDATE/DELETE */ + Index resultRelation; /* rtable index of target relation for + * INSERT/UPDATE/DELETE; 0 for SELECT */ Oid fs_server; /* OID of foreign server */ List *fdw_exprs; /* expressions that FDW may evaluate */ List *fdw_private; /* private data for FDW */