From 7ebb8b2b8ec9458ad7b545354a760e8e93122420 Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvherre@alvh.no-ip.org>
Date: Wed, 27 Jan 2021 18:49:21 -0300
Subject: [PATCH] Remove bogus restriction from BEFORE UPDATE triggers

Reported-by: Phillip Menke <pg@pmenke.de>
Discussion: https://postgr.es/m/16794-350a655580fbb9ae@postgresql.org
---
 src/backend/commands/trigger.c         | 10 ----------
 src/test/regress/expected/triggers.out | 19 +++++++++++++++----
 src/test/regress/sql/triggers.sql      |  7 +++++++
 3 files changed, 22 insertions(+), 14 deletions(-)

diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index 9361a1417b..29d58c6be5 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -2726,16 +2726,6 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
 		{
 			ExecForceStoreHeapTuple(newtuple, newslot, false);
 
-			if (trigger->tgisclone &&
-				!ExecPartitionCheck(relinfo, newslot, estate, false))
-				ereport(ERROR,
-						(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-						 errmsg("moving row to another partition during a BEFORE trigger is not supported"),
-						 errdetail("Before executing trigger \"%s\", the row was to be in partition \"%s.%s\".",
-								   trigger->tgname,
-								   get_namespace_name(RelationGetNamespace(relinfo->ri_RelationDesc)),
-								   RelationGetRelationName(relinfo->ri_RelationDesc))));
-
 			/*
 			 * If the tuple returned by the trigger / being stored, is the old
 			 * row version, and the heap tuple passed to the trigger was
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out
index f6610b0585..d243c6ce1e 100644
--- a/src/test/regress/expected/triggers.out
+++ b/src/test/regress/expected/triggers.out
@@ -2359,8 +2359,8 @@ insert into parted values (1, 1, 'uno uno v2');    -- fail
 ERROR:  moving row to another partition during a BEFORE FOR EACH ROW trigger is not supported
 DETAIL:  Before executing trigger "t", the row was to be in partition "public.parted_1_1".
 update parted set c = c || 'v3';                   -- fail
-ERROR:  moving row to another partition during a BEFORE trigger is not supported
-DETAIL:  Before executing trigger "t", the row was to be in partition "public.parted_1_1".
+ERROR:  no partition of relation "parted" found for row
+DETAIL:  Partition key of the failing row contains (a) = (2).
 create or replace function parted_trigfunc() returns trigger language plpgsql as $$
 begin
   new.b = new.b + 1;
@@ -2371,8 +2371,8 @@ insert into parted values (1, 1, 'uno uno v4');    -- fail
 ERROR:  moving row to another partition during a BEFORE FOR EACH ROW trigger is not supported
 DETAIL:  Before executing trigger "t", the row was to be in partition "public.parted_1_1".
 update parted set c = c || 'v5';                   -- fail
-ERROR:  moving row to another partition during a BEFORE trigger is not supported
-DETAIL:  Before executing trigger "t", the row was to be in partition "public.parted_1_1".
+ERROR:  no partition of relation "parted_1" found for row
+DETAIL:  Partition key of the failing row contains (b) = (2).
 create or replace function parted_trigfunc() returns trigger language plpgsql as $$
 begin
   new.c = new.c || ' and so';
@@ -2388,6 +2388,17 @@ select tableoid::regclass, * from parted;
  parted_1_1 | 1 | 1 | uno uno and so v6 and so
 (2 rows)
 
+-- update itself moves tuple to new partition; trigger still works
+truncate table parted;
+create table parted_2 partition of parted for values in (2);
+insert into parted values (1, 1, 'uno uno v5');
+update parted set a = 2;
+select tableoid::regclass, * from parted;
+ tableoid | a | b |                c                
+----------+---+---+---------------------------------
+ parted_2 | 2 | 1 | uno uno v5 and so and so and so
+(1 row)
+
 drop table parted;
 create table parted (a int, b int, c text) partition by list ((a + b));
 create or replace function parted_trigfunc() returns trigger language plpgsql as $$
diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql
index 9c3872eb14..f098ca544c 100644
--- a/src/test/regress/sql/triggers.sql
+++ b/src/test/regress/sql/triggers.sql
@@ -1641,6 +1641,13 @@ insert into parted values (1, 1, 'uno uno');       -- works
 update parted set c = c || ' v6';                   -- works
 select tableoid::regclass, * from parted;
 
+-- update itself moves tuple to new partition; trigger still works
+truncate table parted;
+create table parted_2 partition of parted for values in (2);
+insert into parted values (1, 1, 'uno uno v5');
+update parted set a = 2;
+select tableoid::regclass, * from parted;
+
 drop table parted;
 create table parted (a int, b int, c text) partition by list ((a + b));
 create or replace function parted_trigfunc() returns trigger language plpgsql as $$
-- 
2.20.1

