From d0661fdf84e6d16af5cb59b18360cc08b51f8ab0 Mon Sep 17 00:00:00 2001 From: "Paul A. Jungwirth" Date: Tue, 7 Jul 2026 17:21:34 -0700 Subject: [PATCH v8 3/4] Check FOR PORTION OF against INSTEAD OF triggers during rewriting Move the INSTEAD OF trigger check to the rewriter. This loses the error position but gives the check better locality with where we look up the triggers. Discussion: https://www.postgresql.org/message-id/CAJ7c6TME%2Bix6VRf-2TPnVTsj8qn_hy6sYAOmMhZEivwsu2wS6g%40mail.gmail.com --- src/backend/parser/analyze.c | 11 ----------- src/backend/rewrite/rewriteHandler.c | 8 ++++++++ src/test/regress/expected/updatable_views.out | 8 -------- 3 files changed, 8 insertions(+), 19 deletions(-) diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c index 1e6fbc95964..2932d17a107 100644 --- a/src/backend/parser/analyze.c +++ b/src/backend/parser/analyze.c @@ -1344,17 +1344,6 @@ 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/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index e7ae9cce65f..38f54b57eec 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -4171,6 +4171,14 @@ RewriteQuery(Query *parsetree, List *rewrite_events, int orig_rt_length, */ rt_entry_relation = relation_open(rt_entry->relid, NoLock); + /* We don't support FOR PORTION OF on views with INSTEAD OF triggers. */ + if (parsetree->forPortionOf && + rt_entry_relation->rd_rel->relkind == RELKIND_VIEW && + view_has_instead_trigger(rt_entry_relation, event, NIL)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("views with INSTEAD OF triggers do not support FOR PORTION OF"))); + /* * Rewrite the targetlist as needed for the command type. */ diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out index e6232a5f8c0..9c6bb2219f9 100644 --- a/src/test/regress/expected/updatable_views.out +++ b/src/test/regress/expected/updatable_views.out @@ -4179,28 +4179,20 @@ 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(); -- Forbid INSTEAD OF triggers with FOR PORTION OF even if the FOR PORTION OF -- 2.47.3