1
0
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:
Robert Haas
2016-03-18 13:48:58 -04:00
parent 3422feccca
commit 0bf3ae88af
21 changed files with 1515 additions and 125 deletions

View File

@@ -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;
}

View File

@@ -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;
}