aboutsummaryrefslogtreecommitdiff
path: root/contrib/postgres_fdw/postgres_fdw.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2013-03-12 18:58:13 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2013-03-12 18:58:13 -0400
commit50c19fc76f05124b80fc4c5d20a359c5dbf017af (patch)
tree8a45e85fb18c599fbd03702ca0d47cdf6aaeecb8 /contrib/postgres_fdw/postgres_fdw.c
parenta0c6dfeecfcc860858b04617a9d96eaee1d82c66 (diff)
downloadpostgresql-50c19fc76f05124b80fc4c5d20a359c5dbf017af.tar.gz
postgresql-50c19fc76f05124b80fc4c5d20a359c5dbf017af.zip
Fix contrib/postgres_fdw's handling of column defaults.
Adopt the position that only locally-defined defaults matter. Any defaults defined in the remote database do not affect insertions performed through a foreign table (unless they are for columns not known to the foreign table). While it'd arguably be more useful to permit remote defaults to be used, making that work in a consistent fashion requires far more work than seems possible for 9.3.
Diffstat (limited to 'contrib/postgres_fdw/postgres_fdw.c')
-rw-r--r--contrib/postgres_fdw/postgres_fdw.c43
1 files changed, 33 insertions, 10 deletions
diff --git a/contrib/postgres_fdw/postgres_fdw.c b/contrib/postgres_fdw/postgres_fdw.c
index 95505c8a1c7..58dd12c575a 100644
--- a/contrib/postgres_fdw/postgres_fdw.c
+++ b/contrib/postgres_fdw/postgres_fdw.c
@@ -1023,6 +1023,8 @@ postgresPlanForeignModify(PlannerInfo *root,
int subplan_index)
{
CmdType operation = plan->operation;
+ RangeTblEntry *rte = planner_rt_fetch(resultRelation, root);
+ Relation rel;
StringInfoData sql;
List *targetAttrs = NIL;
List *returningList = NIL;
@@ -1030,15 +1032,33 @@ postgresPlanForeignModify(PlannerInfo *root,
initStringInfo(&sql);
/*
- * Construct a list of the columns that are to be assigned during INSERT
- * or UPDATE. We should transmit only these columns, for performance and
- * to respect any DEFAULT values the remote side may have for other
- * columns. (XXX this will need some re-thinking when we support default
- * expressions for foreign tables.)
+ * Core code already has some lock on each rel being planned, so we can
+ * use NoLock here.
*/
- if (operation == CMD_INSERT || operation == CMD_UPDATE)
+ rel = heap_open(rte->relid, NoLock);
+
+ /*
+ * In an INSERT, we transmit all columns that are defined in the foreign
+ * table. In an UPDATE, we transmit only columns that were explicitly
+ * targets of the UPDATE, so as to avoid unnecessary data transmission.
+ * (We can't do that for INSERT since we would miss sending default values
+ * for columns not listed in the source statement.)
+ */
+ if (operation == CMD_INSERT)
+ {
+ TupleDesc tupdesc = RelationGetDescr(rel);
+ int attnum;
+
+ for (attnum = 1; attnum <= tupdesc->natts; attnum++)
+ {
+ Form_pg_attribute attr = tupdesc->attrs[attnum - 1];
+
+ if (!attr->attisdropped)
+ targetAttrs = lappend_int(targetAttrs, attnum);
+ }
+ }
+ else if (operation == CMD_UPDATE)
{
- RangeTblEntry *rte = planner_rt_fetch(resultRelation, root);
Bitmapset *tmpset = bms_copy(rte->modifiedCols);
AttrNumber col;
@@ -1063,21 +1083,24 @@ postgresPlanForeignModify(PlannerInfo *root,
switch (operation)
{
case CMD_INSERT:
- deparseInsertSql(&sql, root, resultRelation,
+ deparseInsertSql(&sql, root, resultRelation, rel,
targetAttrs, returningList);
break;
case CMD_UPDATE:
- deparseUpdateSql(&sql, root, resultRelation,
+ deparseUpdateSql(&sql, root, resultRelation, rel,
targetAttrs, returningList);
break;
case CMD_DELETE:
- deparseDeleteSql(&sql, root, resultRelation, returningList);
+ deparseDeleteSql(&sql, root, resultRelation, rel,
+ returningList);
break;
default:
elog(ERROR, "unexpected operation: %d", (int) operation);
break;
}
+ heap_close(rel, NoLock);
+
/*
* Build the fdw_private list that will be available to the executor.
* Items in the list must match enum FdwModifyPrivateIndex, above.