From e47bf332d6620d2820e7a93b5475a2a1456bd1c7 Mon Sep 17 00:00:00 2001 From: jian he Date: Fri, 24 Apr 2026 12:43:50 +0800 Subject: [PATCH v7 1/1] FOR PORTION OF guard against FDW discussion: https://postgr.es/m/626986.1776785090%40sss.pgh.pa.us commitfest entry: https://commitfest.postgresql.org/patch/ --- .../postgres_fdw/expected/postgres_fdw.out | 19 +++++++++++++++-- contrib/postgres_fdw/sql/postgres_fdw.sql | 21 +++++++++++++++++-- src/backend/commands/copyfrom.c | 2 +- src/backend/executor/execMain.c | 9 +++++++- src/backend/executor/execPartition.c | 4 ++-- src/backend/executor/nodeModifyTable.c | 2 +- src/backend/parser/analyze.c | 6 ------ src/include/executor/executor.h | 2 +- 8 files changed, 49 insertions(+), 16 deletions(-) diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index 10e87acabef..a0b796a4a12 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -6334,9 +6334,20 @@ DELETE FROM ft2 WHERE c1 = 1200 RETURNING tableoid::regclass; (1 row) -- Test UPDATE FOR PORTION OF +CREATE TABLE ftpp ( + c1 int4range NOT NULL, + c2 int NOT NULL, + c3 text, + c4 daterange NOT NULL +) PARTITION BY RANGE (c2); +ALTER TABLE ftpp ATTACH PARTITION ft8 FOR VALUES FROM (1) TO (150); +UPDATE ftpp FOR PORTION OF c4 FROM '2005-01-01' TO '2006-01-01' +SET c2 = c2 + 1 +WHERE c1 = '[1,2)'; -- error +ERROR: foreign tables don't support FOR PORTION OF UPDATE ft8 FOR PORTION OF c4 FROM '2005-01-01' TO '2006-01-01' SET c2 = c2 + 1 -WHERE c1 = '[1,2)'; +WHERE c1 = '[1,2)'; -- error ERROR: foreign tables don't support FOR PORTION OF SELECT * FROM ft8 WHERE c1 = '[1,2)' ORDER BY c1, c4; c1 | c2 | c3 | c4 @@ -6345,8 +6356,12 @@ SELECT * FROM ft8 WHERE c1 = '[1,2)' ORDER BY c1, c4; (1 row) -- Test DELETE FOR PORTION OF +DELETE FROM ftpp FOR PORTION OF c4 FROM '2005-01-01' TO '2006-01-01' +WHERE c1 = '[2,3)'; -- error +ERROR: foreign tables don't support FOR PORTION OF +ALTER TABLE ftpp DETACH PARTITION ft8; DELETE FROM ft8 FOR PORTION OF c4 FROM '2005-01-01' TO '2006-01-01' -WHERE c1 = '[2,3)'; +WHERE c1 = '[2,3)'; -- error ERROR: foreign tables don't support FOR PORTION OF SELECT * FROM ft8 WHERE c1 = '[2,3)' ORDER BY c1, c4; c1 | c2 | c3 | c4 diff --git a/contrib/postgres_fdw/sql/postgres_fdw.sql b/contrib/postgres_fdw/sql/postgres_fdw.sql index 79ad5be8bf9..bf3f28c56a5 100644 --- a/contrib/postgres_fdw/sql/postgres_fdw.sql +++ b/contrib/postgres_fdw/sql/postgres_fdw.sql @@ -1577,14 +1577,31 @@ DELETE FROM ft2 WHERE c1 = 1200 RETURNING tableoid::regclass; DELETE FROM ft2 WHERE c1 = 1200 RETURNING tableoid::regclass; -- Test UPDATE FOR PORTION OF +CREATE TABLE ftpp ( + c1 int4range NOT NULL, + c2 int NOT NULL, + c3 text, + c4 daterange NOT NULL +) PARTITION BY RANGE (c2); +ALTER TABLE ftpp ATTACH PARTITION ft8 FOR VALUES FROM (1) TO (150); + +UPDATE ftpp FOR PORTION OF c4 FROM '2005-01-01' TO '2006-01-01' +SET c2 = c2 + 1 +WHERE c1 = '[1,2)'; -- error + UPDATE ft8 FOR PORTION OF c4 FROM '2005-01-01' TO '2006-01-01' SET c2 = c2 + 1 -WHERE c1 = '[1,2)'; +WHERE c1 = '[1,2)'; -- error SELECT * FROM ft8 WHERE c1 = '[1,2)' ORDER BY c1, c4; -- Test DELETE FOR PORTION OF +DELETE FROM ftpp FOR PORTION OF c4 FROM '2005-01-01' TO '2006-01-01' +WHERE c1 = '[2,3)'; -- error + +ALTER TABLE ftpp DETACH PARTITION ft8; + DELETE FROM ft8 FOR PORTION OF c4 FROM '2005-01-01' TO '2006-01-01' -WHERE c1 = '[2,3)'; +WHERE c1 = '[2,3)'; -- error SELECT * FROM ft8 WHERE c1 = '[2,3)' ORDER BY c1, c4; -- Test UPDATE/DELETE with RETURNING on a three-table join diff --git a/src/backend/commands/copyfrom.c b/src/backend/commands/copyfrom.c index 64ac3063c61..775b1b5a641 100644 --- a/src/backend/commands/copyfrom.c +++ b/src/backend/commands/copyfrom.c @@ -921,7 +921,7 @@ CopyFrom(CopyFromState cstate) ExecInitResultRelation(estate, resultRelInfo, 1); /* Verify the named relation is a valid target for INSERT */ - CheckValidResultRel(resultRelInfo, CMD_INSERT, ONCONFLICT_NONE, NIL); + CheckValidResultRel(resultRelInfo, CMD_INSERT, ONCONFLICT_NONE, NIL, NULL); ExecOpenIndices(resultRelInfo, false); diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index 4b30f768680..06de3a4461c 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -1063,7 +1063,8 @@ InitPlan(QueryDesc *queryDesc, int eflags) */ void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation, - OnConflictAction onConflictAction, List *mergeActions) + OnConflictAction onConflictAction, List *mergeActions, + ModifyTable *mtnode) { Relation resultRel = resultRelInfo->ri_RelationDesc; FdwRoutine *fdwroutine; @@ -1126,6 +1127,12 @@ CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation, RelationGetRelationName(resultRel)))); break; case RELKIND_FOREIGN_TABLE: + /* We don't support FOR PORTION OF FDW queries. */ + if (mtnode && mtnode->forPortionOf) + ereport(ERROR, + errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("foreign tables don't support FOR PORTION OF")); + /* Okay only if the FDW supports it */ fdwroutine = resultRelInfo->ri_FdwRoutine; switch (operation) diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c index d96d4f9947b..33ec5bfde4c 100644 --- a/src/backend/executor/execPartition.c +++ b/src/backend/executor/execPartition.c @@ -368,7 +368,7 @@ ExecFindPartition(ModifyTableState *mtstate, /* Verify this ResultRelInfo allows INSERTs */ CheckValidResultRel(rri, CMD_INSERT, node ? node->onConflictAction : ONCONFLICT_NONE, - NIL); + NIL, node); /* * Initialize information needed to insert this and @@ -594,7 +594,7 @@ ExecInitPartitionInfo(ModifyTableState *mtstate, EState *estate, * required when the operation is CMD_UPDATE. */ CheckValidResultRel(leaf_part_rri, CMD_INSERT, - node ? node->onConflictAction : ONCONFLICT_NONE, NIL); + node ? node->onConflictAction : ONCONFLICT_NONE, NIL, node); /* * Open partition indices. The user may have asked to check for conflicts diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c index 4cb057ca4f9..7ff7a3a17e5 100644 --- a/src/backend/executor/nodeModifyTable.c +++ b/src/backend/executor/nodeModifyTable.c @@ -5296,7 +5296,7 @@ ExecInitModifyTable(ModifyTable *node, EState *estate, int eflags) * Verify result relation is a valid target for the current operation */ CheckValidResultRel(resultRelInfo, operation, node->onConflictAction, - mergeActions); + mergeActions, node); resultRelInfo++; i++; diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index ffcf25a6be7..04bae9939b9 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -1335,12 +1335,6 @@ transformForPortionOfClause(ParseState *pstate, ForPortionOfExpr *result; Var *rangeVar; - /* We don't support FOR PORTION OF FDW queries. */ - if (targetrel->rd_rel->relkind == RELKIND_FOREIGN_TABLE) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("foreign tables don't support FOR PORTION OF"))); - result = makeNode(ForPortionOfExpr); /* Look up the FOR PORTION OF name requested. */ diff --git a/src/include/executor/executor.h b/src/include/executor/executor.h index 33bbdbfeffb..c690b230b45 100644 --- a/src/include/executor/executor.h +++ b/src/include/executor/executor.h @@ -249,7 +249,7 @@ extern bool ExecCheckPermissions(List *rangeTable, extern bool ExecCheckOneRelPerms(RTEPermissionInfo *perminfo); extern void CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation, OnConflictAction onConflictAction, - List *mergeActions); + List *mergeActions, ModifyTable *mtnode); extern void InitResultRelInfo(ResultRelInfo *resultRelInfo, Relation resultRelationDesc, Index resultRelationIndex, -- 2.34.1