Hi Peter,

Thanks for your attention to this.

> I don't understand the status of this discussion.  The original bug
> report is related to views and INSTEAD OF triggers.  But the last few
> patches that have been posted here appear to be unrelated to that
> specific issue.

That makes two of us. My humble understanding is that there are
several related discussions but they are happening elsewhere now. Feel
free correcting me if this is not the case.

Here I propose to focus on a particular crash and the particular
proposed bugfix, v1-0001. Perhaps it should be rewritten or maybe we
should reject it in favor of another patch. Both are possible
outcomes. Right now I'm only interested in fixing a particular crash.

> I definitely don't like checking volatility at parse time, though.

So.... the last comment from Tom was that he is not happy :) but I'm
not sure about the actionable items. Tom, could you please elaborate a
bit?

-- 
Best regards,
Aleksander Alekseev
From 63b6699d5c03405f36396dd98c54f53a4bcf40d3 Mon Sep 17 00:00:00 2001
From: Aleksander Alekseev <[email protected]>
Date: Tue, 21 Apr 2026 15:46:04 +0300
Subject: [PATCH v1] Forbid FOR PORTION OF on views with INSTEAD OF triggers

Priviously an attempt to use these features together caused a crash.
Oversight of commit 8e72d914c528.

Author: Aleksander Alekseev <[email protected]>
Reviewed-by: TODO FIXME
Discussion: TODO FIXME
---
 src/backend/parser/analyze.c                  | 11 +++++++++
 src/test/regress/expected/updatable_views.out | 24 +++++++++++++++++++
 src/test/regress/sql/updatable_views.sql      | 24 +++++++++++++++++++
 3 files changed, 59 insertions(+)

diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index cb4e5019c2f..4fc0ae7199e 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1333,6 +1333,17 @@ transformForPortionOfClause(ParseState *pstate,
 				(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
 				 errmsg("foreign tables don't support FOR PORTION OF")));
 
+	/* 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 8852160718f..4701938bfe2 100644
--- a/src/test/regress/expected/updatable_views.out
+++ b/src/test/regress/expected/updatable_views.out
@@ -4151,3 +4151,27 @@ 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'
+                         ^
+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 f7646999bd4..30c2db7ad7d 100644
--- a/src/test/regress/sql/updatable_views.sql
+++ b/src/test/regress/sql/updatable_views.sql
@@ -2137,3 +2137,27 @@ 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
+
+drop view uv_fpo_instead_view;
+drop function uv_fpo_instead_trig();
-- 
2.43.0

Reply via email to