Commit 50c19fc7 authored by Tom Lane's avatar Tom Lane

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.
parent a0c6dfee
...@@ -77,7 +77,7 @@ static void deparseReturningList(StringInfo buf, PlannerInfo *root, ...@@ -77,7 +77,7 @@ static void deparseReturningList(StringInfo buf, PlannerInfo *root,
List *returningList); List *returningList);
static void deparseColumnRef(StringInfo buf, int varno, int varattno, static void deparseColumnRef(StringInfo buf, int varno, int varattno,
PlannerInfo *root); PlannerInfo *root);
static void deparseRelation(StringInfo buf, Oid relid); static void deparseRelation(StringInfo buf, Relation rel);
static void deparseStringLiteral(StringInfo buf, const char *val); static void deparseStringLiteral(StringInfo buf, const char *val);
static void deparseExpr(StringInfo buf, Expr *expr, PlannerInfo *root); static void deparseExpr(StringInfo buf, Expr *expr, PlannerInfo *root);
static void deparseVar(StringInfo buf, Var *node, PlannerInfo *root); static void deparseVar(StringInfo buf, Var *node, PlannerInfo *root);
...@@ -387,7 +387,7 @@ deparseSelectSql(StringInfo buf, ...@@ -387,7 +387,7 @@ deparseSelectSql(StringInfo buf,
* Construct FROM clause * Construct FROM clause
*/ */
appendStringInfoString(buf, " FROM "); appendStringInfoString(buf, " FROM ");
deparseRelation(buf, RelationGetRelid(rel)); deparseRelation(buf, rel);
heap_close(rel, NoLock); heap_close(rel, NoLock);
} }
...@@ -499,18 +499,16 @@ appendWhereClause(StringInfo buf, ...@@ -499,18 +499,16 @@ appendWhereClause(StringInfo buf,
* deparse remote INSERT statement * deparse remote INSERT statement
*/ */
void void
deparseInsertSql(StringInfo buf, PlannerInfo *root, Index rtindex, deparseInsertSql(StringInfo buf, PlannerInfo *root,
Index rtindex, Relation rel,
List *targetAttrs, List *returningList) List *targetAttrs, List *returningList)
{ {
RangeTblEntry *rte = planner_rt_fetch(rtindex, root);
Relation rel = heap_open(rte->relid, NoLock);
TupleDesc tupdesc = RelationGetDescr(rel);
AttrNumber pindex; AttrNumber pindex;
bool first; bool first;
ListCell *lc; ListCell *lc;
appendStringInfoString(buf, "INSERT INTO "); appendStringInfoString(buf, "INSERT INTO ");
deparseRelation(buf, rte->relid); deparseRelation(buf, rel);
if (targetAttrs) if (targetAttrs)
{ {
...@@ -520,9 +518,6 @@ deparseInsertSql(StringInfo buf, PlannerInfo *root, Index rtindex, ...@@ -520,9 +518,6 @@ deparseInsertSql(StringInfo buf, PlannerInfo *root, Index rtindex,
foreach(lc, targetAttrs) foreach(lc, targetAttrs)
{ {
int attnum = lfirst_int(lc); int attnum = lfirst_int(lc);
Form_pg_attribute attr = tupdesc->attrs[attnum - 1];
Assert(!attr->attisdropped);
if (!first) if (!first)
appendStringInfoString(buf, ", "); appendStringInfoString(buf, ", ");
...@@ -552,26 +547,22 @@ deparseInsertSql(StringInfo buf, PlannerInfo *root, Index rtindex, ...@@ -552,26 +547,22 @@ deparseInsertSql(StringInfo buf, PlannerInfo *root, Index rtindex,
if (returningList) if (returningList)
deparseReturningList(buf, root, rtindex, rel, returningList); deparseReturningList(buf, root, rtindex, rel, returningList);
heap_close(rel, NoLock);
} }
/* /*
* deparse remote UPDATE statement * deparse remote UPDATE statement
*/ */
void void
deparseUpdateSql(StringInfo buf, PlannerInfo *root, Index rtindex, deparseUpdateSql(StringInfo buf, PlannerInfo *root,
Index rtindex, Relation rel,
List *targetAttrs, List *returningList) List *targetAttrs, List *returningList)
{ {
RangeTblEntry *rte = planner_rt_fetch(rtindex, root);
Relation rel = heap_open(rte->relid, NoLock);
TupleDesc tupdesc = RelationGetDescr(rel);
AttrNumber pindex; AttrNumber pindex;
bool first; bool first;
ListCell *lc; ListCell *lc;
appendStringInfoString(buf, "UPDATE "); appendStringInfoString(buf, "UPDATE ");
deparseRelation(buf, rte->relid); deparseRelation(buf, rel);
appendStringInfoString(buf, " SET "); appendStringInfoString(buf, " SET ");
pindex = 2; /* ctid is always the first param */ pindex = 2; /* ctid is always the first param */
...@@ -579,9 +570,6 @@ deparseUpdateSql(StringInfo buf, PlannerInfo *root, Index rtindex, ...@@ -579,9 +570,6 @@ deparseUpdateSql(StringInfo buf, PlannerInfo *root, Index rtindex,
foreach(lc, targetAttrs) foreach(lc, targetAttrs)
{ {
int attnum = lfirst_int(lc); int attnum = lfirst_int(lc);
Form_pg_attribute attr = tupdesc->attrs[attnum - 1];
Assert(!attr->attisdropped);
if (!first) if (!first)
appendStringInfoString(buf, ", "); appendStringInfoString(buf, ", ");
...@@ -595,30 +583,22 @@ deparseUpdateSql(StringInfo buf, PlannerInfo *root, Index rtindex, ...@@ -595,30 +583,22 @@ deparseUpdateSql(StringInfo buf, PlannerInfo *root, Index rtindex,
if (returningList) if (returningList)
deparseReturningList(buf, root, rtindex, rel, returningList); deparseReturningList(buf, root, rtindex, rel, returningList);
heap_close(rel, NoLock);
} }
/* /*
* deparse remote DELETE statement * deparse remote DELETE statement
*/ */
void void
deparseDeleteSql(StringInfo buf, PlannerInfo *root, Index rtindex, deparseDeleteSql(StringInfo buf, PlannerInfo *root,
Index rtindex, Relation rel,
List *returningList) List *returningList)
{ {
RangeTblEntry *rte = planner_rt_fetch(rtindex, root);
appendStringInfoString(buf, "DELETE FROM "); appendStringInfoString(buf, "DELETE FROM ");
deparseRelation(buf, rte->relid); deparseRelation(buf, rel);
appendStringInfoString(buf, " WHERE ctid = $1"); appendStringInfoString(buf, " WHERE ctid = $1");
if (returningList) if (returningList)
{
Relation rel = heap_open(rte->relid, NoLock);
deparseReturningList(buf, root, rtindex, rel, returningList); deparseReturningList(buf, root, rtindex, rel, returningList);
heap_close(rel, NoLock);
}
} }
/* /*
...@@ -653,12 +633,11 @@ deparseReturningList(StringInfo buf, PlannerInfo *root, ...@@ -653,12 +633,11 @@ deparseReturningList(StringInfo buf, PlannerInfo *root,
void void
deparseAnalyzeSizeSql(StringInfo buf, Relation rel) deparseAnalyzeSizeSql(StringInfo buf, Relation rel)
{ {
Oid relid = RelationGetRelid(rel);
StringInfoData relname; StringInfoData relname;
/* We'll need the remote relation name as a literal. */ /* We'll need the remote relation name as a literal. */
initStringInfo(&relname); initStringInfo(&relname);
deparseRelation(&relname, relid); deparseRelation(&relname, rel);
appendStringInfo(buf, "SELECT pg_catalog.pg_relation_size("); appendStringInfo(buf, "SELECT pg_catalog.pg_relation_size(");
deparseStringLiteral(buf, relname.data); deparseStringLiteral(buf, relname.data);
...@@ -718,7 +697,7 @@ deparseAnalyzeSql(StringInfo buf, Relation rel) ...@@ -718,7 +697,7 @@ deparseAnalyzeSql(StringInfo buf, Relation rel)
* Construct FROM clause * Construct FROM clause
*/ */
appendStringInfoString(buf, " FROM "); appendStringInfoString(buf, " FROM ");
deparseRelation(buf, relid); deparseRelation(buf, rel);
} }
/* /*
...@@ -771,7 +750,7 @@ deparseColumnRef(StringInfo buf, int varno, int varattno, PlannerInfo *root) ...@@ -771,7 +750,7 @@ deparseColumnRef(StringInfo buf, int varno, int varattno, PlannerInfo *root)
* Similarly, schema_name FDW option overrides schema name. * Similarly, schema_name FDW option overrides schema name.
*/ */
static void static void
deparseRelation(StringInfo buf, Oid relid) deparseRelation(StringInfo buf, Relation rel)
{ {
ForeignTable *table; ForeignTable *table;
const char *nspname = NULL; const char *nspname = NULL;
...@@ -779,7 +758,7 @@ deparseRelation(StringInfo buf, Oid relid) ...@@ -779,7 +758,7 @@ deparseRelation(StringInfo buf, Oid relid)
ListCell *lc; ListCell *lc;
/* obtain additional catalog information. */ /* obtain additional catalog information. */
table = GetForeignTable(relid); table = GetForeignTable(RelationGetRelid(rel));
/* /*
* Use value of FDW options if any, instead of the name of object itself. * Use value of FDW options if any, instead of the name of object itself.
...@@ -799,9 +778,9 @@ deparseRelation(StringInfo buf, Oid relid) ...@@ -799,9 +778,9 @@ deparseRelation(StringInfo buf, Oid relid)
* that doesn't seem worth the trouble. * that doesn't seem worth the trouble.
*/ */
if (nspname == NULL) if (nspname == NULL)
nspname = get_namespace_name(get_rel_namespace(relid)); nspname = get_namespace_name(RelationGetNamespace(rel));
if (relname == NULL) if (relname == NULL)
relname = get_rel_name(relid); relname = RelationGetRelationName(rel);
appendStringInfo(buf, "%s.%s", appendStringInfo(buf, "%s.%s",
quote_identifier(nspname), quote_identifier(relname)); quote_identifier(nspname), quote_identifier(relname));
......
...@@ -56,22 +56,22 @@ CREATE FOREIGN TABLE ft1 ( ...@@ -56,22 +56,22 @@ CREATE FOREIGN TABLE ft1 (
c4 timestamptz, c4 timestamptz,
c5 timestamp, c5 timestamp,
c6 varchar(10), c6 varchar(10),
c7 char(10), c7 char(10) default 'ft1',
c8 user_enum c8 user_enum
) SERVER loopback; ) SERVER loopback;
ALTER FOREIGN TABLE ft1 DROP COLUMN c0; ALTER FOREIGN TABLE ft1 DROP COLUMN c0;
CREATE FOREIGN TABLE ft2 ( CREATE FOREIGN TABLE ft2 (
c0 int,
c1 int NOT NULL, c1 int NOT NULL,
c2 int NOT NULL, c2 int NOT NULL,
cx int,
c3 text, c3 text,
c4 timestamptz, c4 timestamptz,
c5 timestamp, c5 timestamp,
c6 varchar(10), c6 varchar(10),
c7 char(10), c7 char(10) default 'ft2',
c8 user_enum c8 user_enum
) SERVER loopback; ) SERVER loopback;
ALTER FOREIGN TABLE ft2 DROP COLUMN c0; ALTER FOREIGN TABLE ft2 DROP COLUMN cx;
-- =================================================================== -- ===================================================================
-- tests for validator -- tests for validator
-- =================================================================== -- ===================================================================
...@@ -737,11 +737,11 @@ COMMIT; ...@@ -737,11 +737,11 @@ COMMIT;
EXPLAIN (verbose, costs off) EXPLAIN (verbose, costs off)
INSERT INTO ft2 (c1,c2,c3) SELECT c1+1000,c2+100, c3 || c3 FROM ft2 LIMIT 20; INSERT INTO ft2 (c1,c2,c3) SELECT c1+1000,c2+100, c3 || c3 FROM ft2 LIMIT 20;
QUERY PLAN QUERY PLAN
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Insert on public.ft2 Insert on public.ft2
Remote SQL: INSERT INTO "S 1"."T 1"("C 1", c2, c3) VALUES ($1, $2, $3) Remote SQL: INSERT INTO "S 1"."T 1"("C 1", c2, c3, c4, c5, c6, c7, c8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
-> Subquery Scan on "*SELECT*" -> Subquery Scan on "*SELECT*"
Output: NULL::integer, "*SELECT*"."?column?", "*SELECT*"."?column?_1", "*SELECT*"."?column?_2", NULL::timestamp with time zone, NULL::timestamp without time zone, NULL::character varying, NULL::bpchar, NULL::user_enum Output: "*SELECT*"."?column?", "*SELECT*"."?column?_1", NULL::integer, "*SELECT*"."?column?_2", NULL::timestamp with time zone, NULL::timestamp without time zone, NULL::character varying, 'ft2 '::character(10), NULL::user_enum
-> Limit -> Limit
Output: ((ft2_1.c1 + 1000)), ((ft2_1.c2 + 100)), ((ft2_1.c3 || ft2_1.c3)) Output: ((ft2_1.c1 + 1000)), ((ft2_1.c2 + 100)), ((ft2_1.c3 || ft2_1.c3))
-> Foreign Scan on public.ft2 ft2_1 -> Foreign Scan on public.ft2 ft2_1
...@@ -753,10 +753,10 @@ INSERT INTO ft2 (c1,c2,c3) SELECT c1+1000,c2+100, c3 || c3 FROM ft2 LIMIT 20; ...@@ -753,10 +753,10 @@ INSERT INTO ft2 (c1,c2,c3) SELECT c1+1000,c2+100, c3 || c3 FROM ft2 LIMIT 20;
INSERT INTO ft2 (c1,c2,c3) INSERT INTO ft2 (c1,c2,c3)
VALUES (1101,201,'aaa'), (1102,202,'bbb'), (1103,203,'ccc') RETURNING *; VALUES (1101,201,'aaa'), (1102,202,'bbb'), (1103,203,'ccc') RETURNING *;
c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8
------+-----+-----+----+----+----+----+---- ------+-----+-----+----+----+----+------------+----
1101 | 201 | aaa | | | | | 1101 | 201 | aaa | | | | ft2 |
1102 | 202 | bbb | | | | | 1102 | 202 | bbb | | | | ft2 |
1103 | 203 | ccc | | | | | 1103 | 203 | ccc | | | | ft2 |
(3 rows) (3 rows)
INSERT INTO ft2 (c1,c2,c3) VALUES (1104,204,'ddd'), (1105,205,'eee'); INSERT INTO ft2 (c1,c2,c3) VALUES (1104,204,'ddd'), (1105,205,'eee');
...@@ -864,23 +864,23 @@ UPDATE ft2 SET c2 = c2 + 400, c3 = c3 || '_update7' WHERE c1 % 10 = 7 RETURNING ...@@ -864,23 +864,23 @@ UPDATE ft2 SET c2 = c2 + 400, c3 = c3 || '_update7' WHERE c1 % 10 = 7 RETURNING
977 | 407 | 00977_update7 | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7 | 7 | foo 977 | 407 | 00977_update7 | Thu Mar 19 00:00:00 1970 PST | Thu Mar 19 00:00:00 1970 | 7 | 7 | foo
987 | 407 | 00987_update7 | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7 | 7 | foo 987 | 407 | 00987_update7 | Sun Mar 29 00:00:00 1970 PST | Sun Mar 29 00:00:00 1970 | 7 | 7 | foo
997 | 407 | 00997_update7 | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7 | 7 | foo 997 | 407 | 00997_update7 | Wed Apr 08 00:00:00 1970 PST | Wed Apr 08 00:00:00 1970 | 7 | 7 | foo
1007 | 507 | 0000700007_update7 | | | | | 1007 | 507 | 0000700007_update7 | | | | ft2 |
1017 | 507 | 0001700017_update7 | | | | | 1017 | 507 | 0001700017_update7 | | | | ft2 |
(102 rows) (102 rows)
EXPLAIN (verbose, costs off) EXPLAIN (verbose, costs off)
UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9' UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9', c7 = DEFAULT
FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9; FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9;
QUERY PLAN QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------- -------------------------------------------------------------------------------------------------------------------------------------------------------------------
Update on public.ft2 Update on public.ft2
Remote SQL: UPDATE "S 1"."T 1" SET c2 = $2, c3 = $3 WHERE ctid = $1 Remote SQL: UPDATE "S 1"."T 1" SET c2 = $2, c3 = $3, c7 = $4 WHERE ctid = $1
-> Hash Join -> Hash Join
Output: NULL::integer, ft2.c1, (ft2.c2 + 500), (ft2.c3 || '_update9'::text), ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft2.ctid, ft1.* Output: ft2.c1, (ft2.c2 + 500), NULL::integer, (ft2.c3 || '_update9'::text), ft2.c4, ft2.c5, ft2.c6, 'ft2 '::character(10), ft2.c8, ft2.ctid, ft1.*
Hash Cond: (ft2.c2 = ft1.c1) Hash Cond: (ft2.c2 = ft1.c1)
-> Foreign Scan on public.ft2 -> Foreign Scan on public.ft2
Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft2.ctid Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c8, ft2.ctid
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8, ctid FROM "S 1"."T 1" FOR UPDATE Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, NULL, c8, ctid FROM "S 1"."T 1" FOR UPDATE
-> Hash -> Hash
Output: ft1.*, ft1.c1 Output: ft1.*, ft1.c1
-> Foreign Scan on public.ft1 -> Foreign Scan on public.ft1
...@@ -888,7 +888,7 @@ UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9' ...@@ -888,7 +888,7 @@ UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9'
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((("C 1" % 10) = 9)) Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE ((("C 1" % 10) = 9))
(13 rows) (13 rows)
UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9' UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9', c7 = DEFAULT
FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9; FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9;
DELETE FROM ft2 WHERE c1 % 10 = 5 RETURNING *; DELETE FROM ft2 WHERE c1 % 10 = 5 RETURNING *;
c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8
...@@ -993,9 +993,9 @@ DELETE FROM ft2 WHERE c1 % 10 = 5 RETURNING *; ...@@ -993,9 +993,9 @@ DELETE FROM ft2 WHERE c1 % 10 = 5 RETURNING *;
975 | 5 | 00975 | Tue Mar 17 00:00:00 1970 PST | Tue Mar 17 00:00:00 1970 | 5 | 5 | foo 975 | 5 | 00975 | Tue Mar 17 00:00:00 1970 PST | Tue Mar 17 00:00:00 1970 | 5 | 5 | foo
985 | 5 | 00985 | Fri Mar 27 00:00:00 1970 PST | Fri Mar 27 00:00:00 1970 | 5 | 5 | foo 985 | 5 | 00985 | Fri Mar 27 00:00:00 1970 PST | Fri Mar 27 00:00:00 1970 | 5 | 5 | foo
995 | 5 | 00995 | Mon Apr 06 00:00:00 1970 PST | Mon Apr 06 00:00:00 1970 | 5 | 5 | foo 995 | 5 | 00995 | Mon Apr 06 00:00:00 1970 PST | Mon Apr 06 00:00:00 1970 | 5 | 5 | foo
1005 | 105 | 0000500005 | | | | | 1005 | 105 | 0000500005 | | | | ft2 |
1015 | 105 | 0001500015 | | | | | 1015 | 105 | 0001500015 | | | | ft2 |
1105 | 205 | eee | | | | | 1105 | 205 | eee | | | | ft2 |
(103 rows) (103 rows)
EXPLAIN (verbose, costs off) EXPLAIN (verbose, costs off)
...@@ -1842,8 +1842,7 @@ SELECT c1,c2,c3,c4 FROM ft2 ORDER BY c1; ...@@ -1842,8 +1842,7 @@ SELECT c1,c2,c3,c4 FROM ft2 ORDER BY c1;
1104 | 204 | ddd | 1104 | 204 | ddd |
(819 rows) (819 rows)
-- Test that defaults and triggers on remote table work as expected -- Test that trigger on remote table works as expected
ALTER TABLE "S 1"."T 1" ALTER c6 SET DEFAULT '(^-^;)';
CREATE OR REPLACE FUNCTION "S 1".F_BRTRIG() RETURNS trigger AS $$ CREATE OR REPLACE FUNCTION "S 1".F_BRTRIG() RETURNS trigger AS $$
BEGIN BEGIN
NEW.c3 = NEW.c3 || '_trig_update'; NEW.c3 = NEW.c3 || '_trig_update';
...@@ -1854,19 +1853,19 @@ CREATE TRIGGER t1_br_insert BEFORE INSERT OR UPDATE ...@@ -1854,19 +1853,19 @@ CREATE TRIGGER t1_br_insert BEFORE INSERT OR UPDATE
ON "S 1"."T 1" FOR EACH ROW EXECUTE PROCEDURE "S 1".F_BRTRIG(); ON "S 1"."T 1" FOR EACH ROW EXECUTE PROCEDURE "S 1".F_BRTRIG();
INSERT INTO ft2 (c1,c2,c3) VALUES (1208, 218, 'fff') RETURNING *; INSERT INTO ft2 (c1,c2,c3) VALUES (1208, 218, 'fff') RETURNING *;
c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8
------+-----+-----------------+----+----+--------+----+---- ------+-----+-----------------+----+----+----+------------+----
1208 | 218 | fff_trig_update | | | (^-^;) | | 1208 | 218 | fff_trig_update | | | | ft2 |
(1 row) (1 row)
INSERT INTO ft2 (c1,c2,c3,c6) VALUES (1218, 218, 'ggg', '(--;') RETURNING *; INSERT INTO ft2 (c1,c2,c3,c6) VALUES (1218, 218, 'ggg', '(--;') RETURNING *;
c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8
------+-----+-----------------+----+----+------+----+---- ------+-----+-----------------+----+----+------+------------+----
1218 | 218 | ggg_trig_update | | | (--; | | 1218 | 218 | ggg_trig_update | | | (--; | ft2 |
(1 row) (1 row)
UPDATE ft2 SET c2 = c2 + 600 WHERE c1 % 10 = 8 RETURNING *; UPDATE ft2 SET c2 = c2 + 600 WHERE c1 % 10 = 8 RETURNING *;
c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8 c1 | c2 | c3 | c4 | c5 | c6 | c7 | c8
------+-----+-----------------------------+------------------------------+--------------------------+--------+------------+----- ------+-----+-----------------------------+------------------------------+--------------------------+------+------------+-----
8 | 608 | 00008_trig_update | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8 | 8 | foo 8 | 608 | 00008_trig_update | Fri Jan 09 00:00:00 1970 PST | Fri Jan 09 00:00:00 1970 | 8 | 8 | foo
18 | 608 | 00018_trig_update | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8 | 8 | foo 18 | 608 | 00018_trig_update | Mon Jan 19 00:00:00 1970 PST | Mon Jan 19 00:00:00 1970 | 8 | 8 | foo
28 | 608 | 00028_trig_update | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8 | 8 | foo 28 | 608 | 00028_trig_update | Thu Jan 29 00:00:00 1970 PST | Thu Jan 29 00:00:00 1970 | 8 | 8 | foo
...@@ -1967,10 +1966,10 @@ UPDATE ft2 SET c2 = c2 + 600 WHERE c1 % 10 = 8 RETURNING *; ...@@ -1967,10 +1966,10 @@ UPDATE ft2 SET c2 = c2 + 600 WHERE c1 % 10 = 8 RETURNING *;
978 | 608 | 00978_trig_update | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8 | 8 | foo 978 | 608 | 00978_trig_update | Fri Mar 20 00:00:00 1970 PST | Fri Mar 20 00:00:00 1970 | 8 | 8 | foo
988 | 608 | 00988_trig_update | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8 | 8 | foo 988 | 608 | 00988_trig_update | Mon Mar 30 00:00:00 1970 PST | Mon Mar 30 00:00:00 1970 | 8 | 8 | foo
998 | 608 | 00998_trig_update | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8 | 8 | foo 998 | 608 | 00998_trig_update | Thu Apr 09 00:00:00 1970 PST | Thu Apr 09 00:00:00 1970 | 8 | 8 | foo
1008 | 708 | 0000800008_trig_update | | | | | 1008 | 708 | 0000800008_trig_update | | | | ft2 |
1018 | 708 | 0001800018_trig_update | | | | | 1018 | 708 | 0001800018_trig_update | | | | ft2 |
1208 | 818 | fff_trig_update_trig_update | | | (^-^;) | | 1208 | 818 | fff_trig_update_trig_update | | | | ft2 |
1218 | 818 | ggg_trig_update_trig_update | | | (--; | | 1218 | 818 | ggg_trig_update_trig_update | | | (--; | ft2 |
(104 rows) (104 rows)
-- Test errors thrown on remote side during update -- Test errors thrown on remote side during update
...@@ -1978,11 +1977,11 @@ ALTER TABLE "S 1"."T 1" ADD CONSTRAINT c2positive CHECK (c2 >= 0); ...@@ -1978,11 +1977,11 @@ ALTER TABLE "S 1"."T 1" ADD CONSTRAINT c2positive CHECK (c2 >= 0);
INSERT INTO ft1(c1, c2) VALUES(11, 12); -- duplicate key INSERT INTO ft1(c1, c2) VALUES(11, 12); -- duplicate key
ERROR: duplicate key value violates unique constraint "t1_pkey" ERROR: duplicate key value violates unique constraint "t1_pkey"
DETAIL: Key ("C 1")=(11) already exists. DETAIL: Key ("C 1")=(11) already exists.
CONTEXT: Remote SQL command: INSERT INTO "S 1"."T 1"("C 1", c2) VALUES ($1, $2) CONTEXT: Remote SQL command: INSERT INTO "S 1"."T 1"("C 1", c2, c3, c4, c5, c6, c7, c8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
INSERT INTO ft1(c1, c2) VALUES(1111, -2); -- c2positive INSERT INTO ft1(c1, c2) VALUES(1111, -2); -- c2positive
ERROR: new row for relation "T 1" violates check constraint "c2positive" ERROR: new row for relation "T 1" violates check constraint "c2positive"
DETAIL: Failing row contains (1111, -2, null, null, null, (^-^;), null, null). DETAIL: Failing row contains (1111, -2, null, null, null, null, ft1 , null).
CONTEXT: Remote SQL command: INSERT INTO "S 1"."T 1"("C 1", c2) VALUES ($1, $2) CONTEXT: Remote SQL command: INSERT INTO "S 1"."T 1"("C 1", c2, c3, c4, c5, c6, c7, c8) VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
UPDATE ft1 SET c2 = -c2 WHERE c1 = 1; -- c2positive UPDATE ft1 SET c2 = -c2 WHERE c1 = 1; -- c2positive
ERROR: new row for relation "T 1" violates check constraint "c2positive" ERROR: new row for relation "T 1" violates check constraint "c2positive"
DETAIL: Failing row contains (1, -1, 00001_trig_update, 1970-01-02 08:00:00+00, 1970-01-02 00:00:00, 1, 1 , foo). DETAIL: Failing row contains (1, -1, 00001_trig_update, 1970-01-02 08:00:00+00, 1970-01-02 00:00:00, 1, 1 , foo).
......
...@@ -1023,6 +1023,8 @@ postgresPlanForeignModify(PlannerInfo *root, ...@@ -1023,6 +1023,8 @@ postgresPlanForeignModify(PlannerInfo *root,
int subplan_index) int subplan_index)
{ {
CmdType operation = plan->operation; CmdType operation = plan->operation;
RangeTblEntry *rte = planner_rt_fetch(resultRelation, root);
Relation rel;
StringInfoData sql; StringInfoData sql;
List *targetAttrs = NIL; List *targetAttrs = NIL;
List *returningList = NIL; List *returningList = NIL;
...@@ -1030,15 +1032,33 @@ postgresPlanForeignModify(PlannerInfo *root, ...@@ -1030,15 +1032,33 @@ postgresPlanForeignModify(PlannerInfo *root,
initStringInfo(&sql); initStringInfo(&sql);
/* /*
* Construct a list of the columns that are to be assigned during INSERT * Core code already has some lock on each rel being planned, so we can
* or UPDATE. We should transmit only these columns, for performance and * use NoLock here.
* 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.)
*/ */
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); Bitmapset *tmpset = bms_copy(rte->modifiedCols);
AttrNumber col; AttrNumber col;
...@@ -1063,21 +1083,24 @@ postgresPlanForeignModify(PlannerInfo *root, ...@@ -1063,21 +1083,24 @@ postgresPlanForeignModify(PlannerInfo *root,
switch (operation) switch (operation)
{ {
case CMD_INSERT: case CMD_INSERT:
deparseInsertSql(&sql, root, resultRelation, deparseInsertSql(&sql, root, resultRelation, rel,
targetAttrs, returningList); targetAttrs, returningList);
break; break;
case CMD_UPDATE: case CMD_UPDATE:
deparseUpdateSql(&sql, root, resultRelation, deparseUpdateSql(&sql, root, resultRelation, rel,
targetAttrs, returningList); targetAttrs, returningList);
break; break;
case CMD_DELETE: case CMD_DELETE:
deparseDeleteSql(&sql, root, resultRelation, returningList); deparseDeleteSql(&sql, root, resultRelation, rel,
returningList);
break; break;
default: default:
elog(ERROR, "unexpected operation: %d", (int) operation); elog(ERROR, "unexpected operation: %d", (int) operation);
break; break;
} }
heap_close(rel, NoLock);
/* /*
* Build the fdw_private list that will be available to the executor. * Build the fdw_private list that will be available to the executor.
* Items in the list must match enum FdwModifyPrivateIndex, above. * Items in the list must match enum FdwModifyPrivateIndex, above.
......
...@@ -53,11 +53,14 @@ extern void appendWhereClause(StringInfo buf, ...@@ -53,11 +53,14 @@ extern void appendWhereClause(StringInfo buf,
PlannerInfo *root, PlannerInfo *root,
List *exprs, List *exprs,
bool is_first); bool is_first);
extern void deparseInsertSql(StringInfo buf, PlannerInfo *root, Index rtindex, extern void deparseInsertSql(StringInfo buf, PlannerInfo *root,
Index rtindex, Relation rel,
List *targetAttrs, List *returningList); List *targetAttrs, List *returningList);
extern void deparseUpdateSql(StringInfo buf, PlannerInfo *root, Index rtindex, extern void deparseUpdateSql(StringInfo buf, PlannerInfo *root,
Index rtindex, Relation rel,
List *targetAttrs, List *returningList); List *targetAttrs, List *returningList);
extern void deparseDeleteSql(StringInfo buf, PlannerInfo *root, Index rtindex, extern void deparseDeleteSql(StringInfo buf, PlannerInfo *root,
Index rtindex, Relation rel,
List *returningList); List *returningList);
extern void deparseAnalyzeSizeSql(StringInfo buf, Relation rel); extern void deparseAnalyzeSizeSql(StringInfo buf, Relation rel);
extern void deparseAnalyzeSql(StringInfo buf, Relation rel); extern void deparseAnalyzeSql(StringInfo buf, Relation rel);
......
...@@ -63,23 +63,23 @@ CREATE FOREIGN TABLE ft1 ( ...@@ -63,23 +63,23 @@ CREATE FOREIGN TABLE ft1 (
c4 timestamptz, c4 timestamptz,
c5 timestamp, c5 timestamp,
c6 varchar(10), c6 varchar(10),
c7 char(10), c7 char(10) default 'ft1',
c8 user_enum c8 user_enum
) SERVER loopback; ) SERVER loopback;
ALTER FOREIGN TABLE ft1 DROP COLUMN c0; ALTER FOREIGN TABLE ft1 DROP COLUMN c0;
CREATE FOREIGN TABLE ft2 ( CREATE FOREIGN TABLE ft2 (
c0 int,
c1 int NOT NULL, c1 int NOT NULL,
c2 int NOT NULL, c2 int NOT NULL,
cx int,
c3 text, c3 text,
c4 timestamptz, c4 timestamptz,
c5 timestamp, c5 timestamp,
c6 varchar(10), c6 varchar(10),
c7 char(10), c7 char(10) default 'ft2',
c8 user_enum c8 user_enum
) SERVER loopback; ) SERVER loopback;
ALTER FOREIGN TABLE ft2 DROP COLUMN c0; ALTER FOREIGN TABLE ft2 DROP COLUMN cx;
-- =================================================================== -- ===================================================================
-- tests for validator -- tests for validator
...@@ -286,9 +286,9 @@ INSERT INTO ft2 (c1,c2,c3) VALUES (1104,204,'ddd'), (1105,205,'eee'); ...@@ -286,9 +286,9 @@ INSERT INTO ft2 (c1,c2,c3) VALUES (1104,204,'ddd'), (1105,205,'eee');
UPDATE ft2 SET c2 = c2 + 300, c3 = c3 || '_update3' WHERE c1 % 10 = 3; UPDATE ft2 SET c2 = c2 + 300, c3 = c3 || '_update3' WHERE c1 % 10 = 3;
UPDATE ft2 SET c2 = c2 + 400, c3 = c3 || '_update7' WHERE c1 % 10 = 7 RETURNING *; UPDATE ft2 SET c2 = c2 + 400, c3 = c3 || '_update7' WHERE c1 % 10 = 7 RETURNING *;
EXPLAIN (verbose, costs off) EXPLAIN (verbose, costs off)
UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9' UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9', c7 = DEFAULT
FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9; FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9;
UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9' UPDATE ft2 SET c2 = ft2.c2 + 500, c3 = ft2.c3 || '_update9', c7 = DEFAULT
FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9; FROM ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 9;
DELETE FROM ft2 WHERE c1 % 10 = 5 RETURNING *; DELETE FROM ft2 WHERE c1 % 10 = 5 RETURNING *;
EXPLAIN (verbose, costs off) EXPLAIN (verbose, costs off)
...@@ -296,8 +296,7 @@ DELETE FROM ft2 USING ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 2; ...@@ -296,8 +296,7 @@ DELETE FROM ft2 USING ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 2;
DELETE FROM ft2 USING ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 2; DELETE FROM ft2 USING ft1 WHERE ft1.c1 = ft2.c2 AND ft1.c1 % 10 = 2;
SELECT c1,c2,c3,c4 FROM ft2 ORDER BY c1; SELECT c1,c2,c3,c4 FROM ft2 ORDER BY c1;
-- Test that defaults and triggers on remote table work as expected -- Test that trigger on remote table works as expected
ALTER TABLE "S 1"."T 1" ALTER c6 SET DEFAULT '(^-^;)';
CREATE OR REPLACE FUNCTION "S 1".F_BRTRIG() RETURNS trigger AS $$ CREATE OR REPLACE FUNCTION "S 1".F_BRTRIG() RETURNS trigger AS $$
BEGIN BEGIN
NEW.c3 = NEW.c3 || '_trig_update'; NEW.c3 = NEW.c3 || '_trig_update';
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment