diff options
| author | Dean Rasheed | 2023-11-09 11:23:42 +0000 |
|---|---|---|
| committer | Dean Rasheed | 2023-11-09 11:23:42 +0000 |
| commit | a4f7d33a904fcd4da7a12d249416dd2c5c5f2c1c (patch) | |
| tree | d785f549246266bf11447f38145b9530df966383 /src/test | |
| parent | 10d34fefc2ab3c12b03772744c24000c44b7a550 (diff) | |
Fix AFTER ROW trigger execution in MERGE cross-partition update.
When executing a MERGE UPDATE action, if the UPDATE is turned into a
cross-partition DELETE then INSERT, do not attempt to invoke AFTER
UPDATE ROW triggers, or any of the other post-update actions in
ExecUpdateEpilogue().
For consistency with a plain UPDATE command, such triggers should not
be fired (and typically fail anyway), and similarly, other post-update
actions, such as WCO/RLS checks should not be executed, and might also
lead to unexpected failures.
Therefore, as with ExecUpdate(), make ExecMergeMatched() return
immediately if ExecUpdateAct() reports that a cross-partition update
was done, to be sure that no further processing is done for that
tuple.
Back-patch to v15, where MERGE was introduced.
Discussion: https://postgr.es/m/CAEZATCWjBgagyNZs02vgDF0DvASYj-iHTFtXG2-nP3orZhmtcw%40mail.gmail.com
Diffstat (limited to 'src/test')
| -rw-r--r-- | src/test/regress/expected/triggers.out | 45 | ||||
| -rw-r--r-- | src/test/regress/sql/triggers.sql | 36 |
2 files changed, 81 insertions, 0 deletions
diff --git a/src/test/regress/expected/triggers.out b/src/test/regress/expected/triggers.out index e8de916dfe2..78e90309238 100644 --- a/src/test/regress/expected/triggers.out +++ b/src/test/regress/expected/triggers.out @@ -2309,6 +2309,51 @@ NOTICE: trigger zzz on parted_trig_1_1 AFTER INSERT for ROW NOTICE: trigger bbb on parted_trig_2 AFTER INSERT for ROW NOTICE: trigger zzz on parted_trig_2 AFTER INSERT for ROW drop table parted_trig; +-- Verify that the correct triggers fire for cross-partition updates +create table parted_trig (a int) partition by list (a); +create table parted_trig1 partition of parted_trig for values in (1); +create table parted_trig2 partition of parted_trig for values in (2); +insert into parted_trig values (1); +create or replace function trigger_notice() returns trigger as $$ + begin + raise notice 'trigger % on % % % for %', TG_NAME, TG_TABLE_NAME, TG_WHEN, TG_OP, TG_LEVEL; + if TG_LEVEL = 'ROW' then + if TG_OP = 'DELETE' then + return OLD; + else + return NEW; + end if; + end if; + return null; + end; + $$ language plpgsql; +create trigger parted_trig_before_stmt before insert or update or delete on parted_trig + for each statement execute procedure trigger_notice(); +create trigger parted_trig_before_row before insert or update or delete on parted_trig + for each row execute procedure trigger_notice(); +create trigger parted_trig_after_row after insert or update or delete on parted_trig + for each row execute procedure trigger_notice(); +create trigger parted_trig_after_stmt after insert or update or delete on parted_trig + for each statement execute procedure trigger_notice(); +update parted_trig set a = 2 where a = 1; +NOTICE: trigger parted_trig_before_stmt on parted_trig BEFORE UPDATE for STATEMENT +NOTICE: trigger parted_trig_before_row on parted_trig1 BEFORE UPDATE for ROW +NOTICE: trigger parted_trig_before_row on parted_trig1 BEFORE DELETE for ROW +NOTICE: trigger parted_trig_before_row on parted_trig2 BEFORE INSERT for ROW +NOTICE: trigger parted_trig_after_row on parted_trig1 AFTER DELETE for ROW +NOTICE: trigger parted_trig_after_row on parted_trig2 AFTER INSERT for ROW +NOTICE: trigger parted_trig_after_stmt on parted_trig AFTER UPDATE for STATEMENT +-- update action in merge should behave the same +merge into parted_trig using (select 1) as ss on true + when matched and a = 2 then update set a = 1; +NOTICE: trigger parted_trig_before_stmt on parted_trig BEFORE UPDATE for STATEMENT +NOTICE: trigger parted_trig_before_row on parted_trig2 BEFORE UPDATE for ROW +NOTICE: trigger parted_trig_before_row on parted_trig2 BEFORE DELETE for ROW +NOTICE: trigger parted_trig_before_row on parted_trig1 BEFORE INSERT for ROW +NOTICE: trigger parted_trig_after_row on parted_trig2 AFTER DELETE for ROW +NOTICE: trigger parted_trig_after_row on parted_trig1 AFTER INSERT for ROW +NOTICE: trigger parted_trig_after_stmt on parted_trig AFTER UPDATE for STATEMENT +drop table parted_trig; -- Verify propagation of trigger arguments to partitions create table parted_trig (a int) partition by list (a); create table parted_trig1 partition of parted_trig for values in (1); diff --git a/src/test/regress/sql/triggers.sql b/src/test/regress/sql/triggers.sql index d29e98d2ac9..46795a9c789 100644 --- a/src/test/regress/sql/triggers.sql +++ b/src/test/regress/sql/triggers.sql @@ -1583,6 +1583,42 @@ create trigger qqq after insert on parted_trig_1_1 for each row execute procedur insert into parted_trig values (50), (1500); drop table parted_trig; +-- Verify that the correct triggers fire for cross-partition updates +create table parted_trig (a int) partition by list (a); +create table parted_trig1 partition of parted_trig for values in (1); +create table parted_trig2 partition of parted_trig for values in (2); +insert into parted_trig values (1); + +create or replace function trigger_notice() returns trigger as $$ + begin + raise notice 'trigger % on % % % for %', TG_NAME, TG_TABLE_NAME, TG_WHEN, TG_OP, TG_LEVEL; + if TG_LEVEL = 'ROW' then + if TG_OP = 'DELETE' then + return OLD; + else + return NEW; + end if; + end if; + return null; + end; + $$ language plpgsql; +create trigger parted_trig_before_stmt before insert or update or delete on parted_trig + for each statement execute procedure trigger_notice(); +create trigger parted_trig_before_row before insert or update or delete on parted_trig + for each row execute procedure trigger_notice(); +create trigger parted_trig_after_row after insert or update or delete on parted_trig + for each row execute procedure trigger_notice(); +create trigger parted_trig_after_stmt after insert or update or delete on parted_trig + for each statement execute procedure trigger_notice(); + +update parted_trig set a = 2 where a = 1; + +-- update action in merge should behave the same +merge into parted_trig using (select 1) as ss on true + when matched and a = 2 then update set a = 1; + +drop table parted_trig; + -- Verify propagation of trigger arguments to partitions create table parted_trig (a int) partition by list (a); create table parted_trig1 partition of parted_trig for values in (1); |
