v7-0001-Forbid-FOR-PORTION-OF-on-views-with-INSTEAD-OF-tr.patch
text/x-patch
Filename: v7-0001-Forbid-FOR-PORTION-OF-on-views-with-INSTEAD-OF-tr.patch
Type: text/x-patch
Part: 1
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v7-0001
Subject: Forbid FOR PORTION OF on views with INSTEAD OF triggers
| File | + | − |
|---|---|---|
| src/backend/parser/analyze.c | 11 | 0 |
| src/test/regress/expected/updatable_views.out | 38 | 0 |
| src/test/regress/sql/updatable_views.sql | 34 | 0 |
From b8765f75ec8084680937c3f0b437e1e19a2cda96 Mon Sep 17 00:00:00 2001
From: Aleksander Alekseev <aleksander@tigerdata.com>
Date: Tue, 7 Jul 2026 17:20:05 -0700
Subject: [PATCH v7 1/3] Forbid FOR PORTION OF on views with INSTEAD OF
triggers
Previously an attempt to use these features together caused a crash.
Oversight of commit 8e72d914c528.
Author: Aleksander Alekseev <aleksander@tigerdata.com>
Discussion: https://www.postgresql.org/message-id/CAJ7c6TME%2Bix6VRf-2TPnVTsj8qn_hy6sYAOmMhZEivwsu2wS6g%40mail.gmail.com
---
src/backend/parser/analyze.c | 11 ++++++
src/test/regress/expected/updatable_views.out | 38 +++++++++++++++++++
src/test/regress/sql/updatable_views.sql | 34 +++++++++++++++++
3 files changed, 83 insertions(+)
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index 2932d17a107..1e6fbc95964 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1344,6 +1344,17 @@ transformForPortionOfClause(ParseState *pstate,
errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("WHERE CURRENT OF with FOR PORTION OF is not implemented"));
+ /* We don't support FOR PORTION OF on views with INSTEAD OF triggers. */
+ if (targetrel->rd_rel->relkind == RELKIND_VIEW &&
+ targetrel->rd_rel->relhastriggers &&
+ targetrel->trigdesc != NULL &&
+ (isUpdate ? targetrel->trigdesc->trig_update_instead_row
+ : targetrel->trigdesc->trig_delete_instead_row))
+ ereport(ERROR,
+ (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+ errmsg("views with INSTEAD OF triggers do not support FOR PORTION OF"),
+ parser_errposition(pstate, forPortionOf->location)));
+
result = makeNode(ForPortionOfExpr);
/* Look up the FOR PORTION OF name requested. */
diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out
index 7b00c742776..acab165ae4c 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -4165,3 +4165,41 @@ select * from base_tab order by a;
drop view base_tab_view;
drop table base_tab;
+-- FOR PORTION OF is not supported on views with INSTEAD OF triggers
+create view uv_fpo_instead_view as select id, valid_at, b from uv_fpo_tab;
+create function uv_fpo_instead_trig() returns trigger language plpgsql as
+$$ begin return null; end $$;
+create trigger uv_fpo_instead_upd_trig
+ instead of update on uv_fpo_instead_view
+ for each row execute function uv_fpo_instead_trig();
+create trigger uv_fpo_instead_del_trig
+ instead of delete on uv_fpo_instead_view
+ for each row execute function uv_fpo_instead_trig();
+update uv_fpo_instead_view
+ for portion of valid_at from '2015-01-01' to '2020-01-01'
+ set b = 99 where id = '[1,1]'; -- error
+ERROR: views with INSTEAD OF triggers do not support FOR PORTION OF
+LINE 2: for portion of valid_at from '2015-01-01' to '2020-01-01'
+ ^
+delete from uv_fpo_instead_view
+ for portion of valid_at from '2017-01-01' to '2022-01-01'
+ where id = '[1,1]'; -- error
+ERROR: views with INSTEAD OF triggers do not support FOR PORTION OF
+LINE 2: for portion of valid_at from '2017-01-01' to '2022-01-01'
+ ^
+-- The check does not depend on which rows match, so it errors even when
+-- no rows do.
+update uv_fpo_instead_view
+ for portion of valid_at from '2015-01-01' to '2020-01-01'
+ set b = 99 where id = '[9,9]'; -- error, even with no matching rows
+ERROR: views with INSTEAD OF triggers do not support FOR PORTION OF
+LINE 2: for portion of valid_at from '2015-01-01' to '2020-01-01'
+ ^
+delete from uv_fpo_instead_view
+ for portion of valid_at from '2017-01-01' to '2022-01-01'
+ where id = '[9,9]'; -- error, even with no matching rows
+ERROR: views with INSTEAD OF triggers do not support FOR PORTION OF
+LINE 2: for portion of valid_at from '2017-01-01' to '2022-01-01'
+ ^
+drop view uv_fpo_instead_view;
+drop function uv_fpo_instead_trig();
diff --git a/src/test/regress/sql/updatable_views.sql b/src/test/regress/sql/updatable_views.sql
index 4a60126ec90..f4a7e0327b0 100644
--- a/src/test/regress/sql/updatable_views.sql
+++ b/src/test/regress/sql/updatable_views.sql
@@ -2148,3 +2148,37 @@ values (1, 2, default, 5, 4, default, 3), (10, 11, 'C value', 14, 13, 100, 12);
select * from base_tab order by a;
drop view base_tab_view;
drop table base_tab;
+
+-- FOR PORTION OF is not supported on views with INSTEAD OF triggers
+create view uv_fpo_instead_view as select id, valid_at, b from uv_fpo_tab;
+
+create function uv_fpo_instead_trig() returns trigger language plpgsql as
+$$ begin return null; end $$;
+
+create trigger uv_fpo_instead_upd_trig
+ instead of update on uv_fpo_instead_view
+ for each row execute function uv_fpo_instead_trig();
+create trigger uv_fpo_instead_del_trig
+ instead of delete on uv_fpo_instead_view
+ for each row execute function uv_fpo_instead_trig();
+
+update uv_fpo_instead_view
+ for portion of valid_at from '2015-01-01' to '2020-01-01'
+ set b = 99 where id = '[1,1]'; -- error
+
+delete from uv_fpo_instead_view
+ for portion of valid_at from '2017-01-01' to '2022-01-01'
+ where id = '[1,1]'; -- error
+
+-- The check does not depend on which rows match, so it errors even when
+-- no rows do.
+update uv_fpo_instead_view
+ for portion of valid_at from '2015-01-01' to '2020-01-01'
+ set b = 99 where id = '[9,9]'; -- error, even with no matching rows
+
+delete from uv_fpo_instead_view
+ for portion of valid_at from '2017-01-01' to '2022-01-01'
+ where id = '[9,9]'; -- error, even with no matching rows
+
+drop view uv_fpo_instead_view;
+drop function uv_fpo_instead_trig();
--
2.47.3