mirror of
https://github.com/postgres/postgres.git
synced 2025-11-06 07:49:08 +03:00
Directly modify foreign tables.
postgres_fdw can now sent an UPDATE or DELETE statement directly to the foreign server in simple cases, rather than sending a SELECT FOR UPDATE statement and then updating or deleting rows one-by-one. Etsuro Fujita, reviewed by Rushabh Lathia, Shigeru Hanada, Kyotaro Horiguchi, Albe Laurenz, Thom Brown, and me.
This commit is contained in:
@@ -4906,6 +4906,7 @@ make_foreignscan(List *qptlist,
|
||||
plan->lefttree = outer_plan;
|
||||
plan->righttree = NULL;
|
||||
node->scan.scanrelid = scanrelid;
|
||||
node->operation = CMD_SELECT;
|
||||
/* fs_server will be filled in by create_foreignscan_plan */
|
||||
node->fs_server = InvalidOid;
|
||||
node->fdw_exprs = fdw_exprs;
|
||||
@@ -6021,6 +6022,7 @@ make_modifytable(PlannerInfo *root,
|
||||
{
|
||||
ModifyTable *node = makeNode(ModifyTable);
|
||||
List *fdw_private_list;
|
||||
Bitmapset *direct_modify_plans;
|
||||
ListCell *lc;
|
||||
int i;
|
||||
|
||||
@@ -6078,12 +6080,14 @@ make_modifytable(PlannerInfo *root,
|
||||
* construct private plan data, and accumulate it all into a list.
|
||||
*/
|
||||
fdw_private_list = NIL;
|
||||
direct_modify_plans = NULL;
|
||||
i = 0;
|
||||
foreach(lc, resultRelations)
|
||||
{
|
||||
Index rti = lfirst_int(lc);
|
||||
FdwRoutine *fdwroutine;
|
||||
List *fdw_private;
|
||||
bool direct_modify;
|
||||
|
||||
/*
|
||||
* If possible, we want to get the FdwRoutine from our RelOptInfo for
|
||||
@@ -6110,7 +6114,23 @@ make_modifytable(PlannerInfo *root,
|
||||
fdwroutine = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* If the target foreign table has any row-level triggers, we can't
|
||||
* modify the foreign table directly.
|
||||
*/
|
||||
direct_modify = false;
|
||||
if (fdwroutine != NULL &&
|
||||
fdwroutine->PlanDirectModify != NULL &&
|
||||
fdwroutine->BeginDirectModify != NULL &&
|
||||
fdwroutine->IterateDirectModify != NULL &&
|
||||
fdwroutine->EndDirectModify != NULL &&
|
||||
!has_row_triggers(root, rti, operation))
|
||||
direct_modify = fdwroutine->PlanDirectModify(root, node, rti, i);
|
||||
if (direct_modify)
|
||||
direct_modify_plans = bms_add_member(direct_modify_plans, i);
|
||||
|
||||
if (!direct_modify &&
|
||||
fdwroutine != NULL &&
|
||||
fdwroutine->PlanForeignModify != NULL)
|
||||
fdw_private = fdwroutine->PlanForeignModify(root, node, rti, i);
|
||||
else
|
||||
@@ -6119,6 +6139,7 @@ make_modifytable(PlannerInfo *root,
|
||||
i++;
|
||||
}
|
||||
node->fdwPrivLists = fdw_private_list;
|
||||
node->fdwDirectModifyPlans = direct_modify_plans;
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
@@ -1540,3 +1540,50 @@ has_unique_index(RelOptInfo *rel, AttrNumber attno)
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* has_row_triggers
|
||||
*
|
||||
* Detect whether the specified relation has any row-level triggers for event.
|
||||
*/
|
||||
bool
|
||||
has_row_triggers(PlannerInfo *root, Index rti, CmdType event)
|
||||
{
|
||||
RangeTblEntry *rte = planner_rt_fetch(rti, root);
|
||||
Relation relation;
|
||||
TriggerDesc *trigDesc;
|
||||
bool result = false;
|
||||
|
||||
/* Assume we already have adequate lock */
|
||||
relation = heap_open(rte->relid, NoLock);
|
||||
|
||||
trigDesc = relation->trigdesc;
|
||||
switch (event)
|
||||
{
|
||||
case CMD_INSERT:
|
||||
if (trigDesc &&
|
||||
(trigDesc->trig_insert_after_row ||
|
||||
trigDesc->trig_insert_before_row))
|
||||
result = true;
|
||||
break;
|
||||
case CMD_UPDATE:
|
||||
if (trigDesc &&
|
||||
(trigDesc->trig_update_after_row ||
|
||||
trigDesc->trig_update_before_row))
|
||||
result = true;
|
||||
break;
|
||||
case CMD_DELETE:
|
||||
if (trigDesc &&
|
||||
(trigDesc->trig_delete_after_row ||
|
||||
trigDesc->trig_delete_before_row))
|
||||
result = true;
|
||||
break;
|
||||
default:
|
||||
elog(ERROR, "unrecognized CmdType: %d", (int) event);
|
||||
break;
|
||||
}
|
||||
|
||||
heap_close(relation, NoLock);
|
||||
return result;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user