-- Test UPDATE 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)';
+ SET c2 = c2 + 1
+ WHERE c1 = '[1,2)'; -- error
ERROR: foreign tables don't support FOR PORTION OF
+DETAIL: "ft8" is a foreign table.
SELECT * FROM ft8 WHERE c1 = '[1,2)' ORDER BY c1, c4;
c1 | c2 | c3 | c4
-------+----+--------+-------------------------
-- Test DELETE FOR PORTION OF
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
+DETAIL: "ft8" is a foreign table.
SELECT * FROM ft8 WHERE c1 = '[2,3)' ORDER BY c1, c4;
c1 | c2 | c3 | c4
-------+----+--------+-------------------------
[2,3) | 3 | AAA002 | [01-01-2000,01-01-2020)
(1 row)
+-- FOR PORTION OF fails if a child partition is a foreign table, even if the
+-- root is not. But a child partition that is pruned doesn't cause an error.
+CREATE TABLE fpo_part_parent (
+ c1 int4range NOT NULL,
+ c2 int NOT NULL,
+ c3 text,
+ c4 daterange NOT NULL
+) PARTITION BY LIST (c2);
+CREATE TABLE fpo_part_local PARTITION OF fpo_part_parent FOR VALUES IN (1);
+INSERT INTO fpo_part_local VALUES ('[1,2)', 1, 'one', '[2024-01-01,2024-12-31)');
+CREATE FOREIGN TABLE fpo_part_foreign
+ PARTITION OF fpo_part_parent FOR VALUES IN (6)
+ SERVER loopback OPTIONS (schema_name 'S 1', table_name 'T 5');
+DELETE FROM fpo_part_parent
+ FOR PORTION OF c4 FROM '2001-01-01' TO '2001-02-01' WHERE c2 = 6; -- error
+ERROR: foreign tables don't support FOR PORTION OF
+DETAIL: "fpo_part_foreign" is a foreign table.
+UPDATE fpo_part_parent
+ FOR PORTION OF c4 FROM '2001-01-01' TO '2001-02-01' SET c3 = 'x' WHERE c2 = 6; -- error
+ERROR: foreign tables don't support FOR PORTION OF
+DETAIL: "fpo_part_foreign" is a foreign table.
+UPDATE fpo_part_parent
+ FOR PORTION OF c4 FROM '2024-06-01' TO '2024-07-01' SET c3 = 'edited' WHERE c2 = 1; -- okay
+DELETE FROM fpo_part_parent
+ FOR PORTION OF c4 FROM '2024-06-01' TO '2024-06-15' WHERE c2 = 1; -- okay
+SELECT c1, c2, c3, c4 FROM fpo_part_local ORDER BY c4;
+ c1 | c2 | c3 | c4
+-------+----+--------+-------------------------
+ [1,2) | 1 | one | [01-01-2024,06-01-2024)
+ [1,2) | 1 | edited | [06-15-2024,07-01-2024)
+ [1,2) | 1 | one | [07-01-2024,12-31-2024)
+(3 rows)
+
+DROP TABLE fpo_part_parent;
-- Test UPDATE/DELETE with RETURNING on a three-table join
INSERT INTO ft2 (c1,c2,c3)
SELECT id, id - 1200, to_char(id, 'FM00000') FROM generate_series(1201, 1300) id;
-- Test UPDATE 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)';
+ SET c2 = c2 + 1
+ WHERE c1 = '[1,2)'; -- error
SELECT * FROM ft8 WHERE c1 = '[1,2)' ORDER BY c1, c4;
-- Test DELETE FOR PORTION OF
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;
+-- FOR PORTION OF fails if a child partition is a foreign table, even if the
+-- root is not. But a child partition that is pruned doesn't cause an error.
+CREATE TABLE fpo_part_parent (
+ c1 int4range NOT NULL,
+ c2 int NOT NULL,
+ c3 text,
+ c4 daterange NOT NULL
+) PARTITION BY LIST (c2);
+CREATE TABLE fpo_part_local PARTITION OF fpo_part_parent FOR VALUES IN (1);
+INSERT INTO fpo_part_local VALUES ('[1,2)', 1, 'one', '[2024-01-01,2024-12-31)');
+CREATE FOREIGN TABLE fpo_part_foreign
+ PARTITION OF fpo_part_parent FOR VALUES IN (6)
+ SERVER loopback OPTIONS (schema_name 'S 1', table_name 'T 5');
+DELETE FROM fpo_part_parent
+ FOR PORTION OF c4 FROM '2001-01-01' TO '2001-02-01' WHERE c2 = 6; -- error
+UPDATE fpo_part_parent
+ FOR PORTION OF c4 FROM '2001-01-01' TO '2001-02-01' SET c3 = 'x' WHERE c2 = 6; -- error
+UPDATE fpo_part_parent
+ FOR PORTION OF c4 FROM '2024-06-01' TO '2024-07-01' SET c3 = 'edited' WHERE c2 = 1; -- okay
+DELETE FROM fpo_part_parent
+ FOR PORTION OF c4 FROM '2024-06-01' TO '2024-06-15' WHERE c2 = 1; -- okay
+SELECT c1, c2, c3, c4 FROM fpo_part_local ORDER BY c4;
+DROP TABLE fpo_part_parent;
+
-- Test UPDATE/DELETE with RETURNING on a three-table join
INSERT INTO ft2 (c1,c2,c3)
SELECT id, id - 1200, to_char(id, 'FM00000') FROM generate_series(1201, 1300) id;
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);
*/
void
CheckValidResultRel(ResultRelInfo *resultRelInfo, CmdType operation,
- OnConflictAction onConflictAction, List *mergeActions)
+ OnConflictAction onConflictAction, List *mergeActions,
+ ModifyTable *mtnode)
{
Relation resultRel = resultRelInfo->ri_RelationDesc;
FdwRoutine *fdwroutine;
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"),
+ errdetail("\"%s\" is a foreign table.",
+ RelationGetRelationName(resultRel)));
+
/* Okay only if the FDW supports it */
fdwroutine = resultRelInfo->ri_FdwRoutine;
switch (operation)
/* Verify this ResultRelInfo allows INSERTs */
CheckValidResultRel(rri, CMD_INSERT,
node ? node->onConflictAction : ONCONFLICT_NONE,
- NIL);
+ NIL, node);
/*
* Initialize information needed to insert this and
* 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
* Verify result relation is a valid target for the current operation
*/
CheckValidResultRel(resultRelInfo, operation, node->onConflictAction,
- mergeActions);
+ mergeActions, node);
resultRelInfo++;
i++;
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. */
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,