diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2013-03-12 18:58:13 -0400 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2013-03-12 18:58:13 -0400 |
commit | 50c19fc76f05124b80fc4c5d20a359c5dbf017af (patch) | |
tree | 8a45e85fb18c599fbd03702ca0d47cdf6aaeecb8 /contrib/postgres_fdw/postgres_fdw.c | |
parent | a0c6dfeecfcc860858b04617a9d96eaee1d82c66 (diff) | |
download | postgresql-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.c | 43 |
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. |