List *fdw_scan_tlist,
Index rtindex);
static TupleTableSlot *apply_returning_filter(PgFdwDirectModifyState *dmstate,
+ ResultRelInfo *resultRelInfo,
TupleTableSlot *slot,
EState *estate);
static void prepare_query_params(PlanState *node,
}
/*
- * Update the operation info.
+ * Update the operation and target relation info.
*/
fscan->operation = operation;
+ fscan->resultRelation = resultRelation;
/*
* Update the fdw_exprs list that will be available to the executor.
* Identify which user to do the remote access as. This should match what
* ExecCheckRTEPerms() does.
*/
- rtindex = estate->es_result_relation_info->ri_RangeTableIndex;
+ rtindex = node->resultRelInfo->ri_RangeTableIndex;
rte = exec_rt_fetch(rtindex, estate);
userid = rte->checkAsUser ? rte->checkAsUser : GetUserId();
{
PgFdwDirectModifyState *dmstate = (PgFdwDirectModifyState *) node->fdw_state;
EState *estate = node->ss.ps.state;
- ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
+ ResultRelInfo *resultRelInfo = node->resultRelInfo;
/*
* If this is the first call after Begin, execute the statement.
{
PgFdwDirectModifyState *dmstate = (PgFdwDirectModifyState *) node->fdw_state;
EState *estate = node->ss.ps.state;
- ResultRelInfo *resultRelInfo = estate->es_result_relation_info;
+ ResultRelInfo *resultRelInfo = node->resultRelInfo;
TupleTableSlot *slot = node->ss.ss_ScanTupleSlot;
TupleTableSlot *resultSlot;
if (dmstate->rel)
resultSlot = slot;
else
- resultSlot = apply_returning_filter(dmstate, slot, estate);
+ resultSlot = apply_returning_filter(dmstate, resultRelInfo, slot, estate);
}
dmstate->next_tuple++;
*/
static TupleTableSlot *
apply_returning_filter(PgFdwDirectModifyState *dmstate,
+ ResultRelInfo *resultRelInfo,
TupleTableSlot *slot,
EState *estate)
{
- ResultRelInfo *relInfo = estate->es_result_relation_info;
TupleDesc resultTupType = RelationGetDescr(dmstate->resultRel);
TupleTableSlot *resultSlot;
Datum *values;
/*
* Use the return tuple slot as a place to store the result tuple.
*/
- resultSlot = ExecGetReturningSlot(estate, relInfo);
+ resultSlot = ExecGetReturningSlot(estate, resultRelInfo);
/*
* Extract all the values of the scan tuple.
To execute the direct modification on the remote server, this function
must rewrite the target subplan with a <structname>ForeignScan</structname> plan
node that executes the direct modification on the remote server. The
- <structfield>operation</structfield> field of the <structname>ForeignScan</structname> must
- be set to the <literal>CmdType</literal> enumeration appropriately; that is,
+ <structfield>operation</structfield> and <structfield>resultRelation</structfield> fields
+ of the <structname>ForeignScan</structname> must be set appropriately.
+ <structfield>operation</structfield> must be set to the <literal>CmdType</literal>
+ enumeration corresponding to the statement kind (that is,
<literal>CMD_UPDATE</literal> for <command>UPDATE</command>,
<literal>CMD_INSERT</literal> for <command>INSERT</command>, and
- <literal>CMD_DELETE</literal> for <command>DELETE</command>.
+ <literal>CMD_DELETE</literal> for <command>DELETE</command>), and the
+ <literal>resultRelation</literal> argument must be copied to the
+ <structfield>resultRelation</structfield> field.
</para>
<para>
needed for the <literal>RETURNING</literal> calculation, returning it in a
tuple table slot (the node's <structfield>ScanTupleSlot</structfield> should be
used for this purpose). The data that was actually inserted, updated
- or deleted must be stored in the
- <literal>es_result_relation_info->ri_projectReturning->pi_exprContext->ecxt_scantuple</literal>
- of the node's <structname>EState</structname>.
+ or deleted must be stored in
+ <literal>node->resultRelInfo->ri_projectReturning->pi_exprContext->ecxt_scantuple</literal>.
Return NULL if no more rows are available.
Note that this is called in a short-lived memory context that will be
reset between invocations. Create a memory context in
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) =
COPY_NODE_FIELD(fdw_recheck_quals);
COPY_BITMAPSET_FIELD(fs_relids);
COPY_SCALAR_FIELD(fsSystemCol);
+ COPY_SCALAR_FIELD(resultRelation);
return newnode;
}
WRITE_NODE_FIELD(fdw_recheck_quals);
WRITE_BITMAPSET_FIELD(fs_relids);
WRITE_BOOL_FIELD(fsSystemCol);
+ WRITE_INT_FIELD(resultRelation);
}
static void
READ_NODE_FIELD(fdw_recheck_quals);
READ_BITMAPSET_FIELD(fs_relids);
READ_BOOL_FIELD(fsSystemCol);
+ READ_INT_FIELD(resultRelation);
READ_DONE();
}
plan->lefttree = outer_plan;
plan->righttree = NULL;
node->scan.scanrelid = scanrelid;
+
+ /* these may be overridden by the FDW's PlanDirectModify callback. */
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;
}
fscan->fs_relids = offset_relid_set(fscan->fs_relids, rtoffset);
+
+ /* Adjust resultRelation if it's valid */
+ if (fscan->resultRelation > 0)
+ fscan->resultRelation += rtoffset;
}
/*
ScanState ss; /* its first field is NodeTag */
ExprState *fdw_recheck_quals; /* original quals not in ss.ps.qual */
Size pscan_len; /* size of parallel coordination information */
+ ResultRelInfo *resultRelInfo; /* result rel info, if UPDATE or DELETE */
/* use struct pointer to avoid including fdwapi.h here */
struct FdwRoutine *fdwroutine;
void *fdw_state; /* foreign-data wrapper can keep state here */
* When the plan node represents a foreign join, scan.scanrelid is zero and
* fs_relids must be consulted to identify the join relation. (fs_relids
* is valid for simple scans as well, but will always match scan.scanrelid.)
+ *
+ * If the FDW's PlanDirectModify() callback decides to repurpose a ForeignScan
+ * node to perform the UPDATE or DELETE operation directly in the remote
+ * server, it sets 'operation' and 'resultRelation' to identify the operation
+ * type and target relation. Note that these fields are only set if the
+ * modification is performed *fully* remotely; otherwise, the modification is
+ * driven by a local ModifyTable node and 'operation' is left to CMD_SELECT.
* ----------------
*/
typedef struct ForeignScan
{
Scan scan;
CmdType operation; /* SELECT/INSERT/UPDATE/DELETE */
+ Index resultRelation; /* direct modification target's RT index */
Oid fs_server; /* OID of foreign server */
List *fdw_exprs; /* expressions that FDW may evaluate */
List *fdw_private; /* private data for FDW */