Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitba9f18a

Browse files
committed
Fix corner case for a BEFORE ROW UPDATE trigger returning OLD.
If the old row has any "missing" attributes that are supposed tobe retrieved from an associated tuple descriptor, the wrong thingshappened because the trigger result is shoved directly into anexecutor slot that lacks the missing-attribute data. Notably,CHECK-constraint verification would incorrectly see those columnsas NULL, and so would RETURNING-list evaluation.Band-aid around this by forcibly expanding the tuple before passingit to the trigger function. (IMO it was a fundamental misdesign toput the missing-attribute data into tuple constraints, which somuch of the system considers to be optional. But we're probablystuck with that now, and will have to continue to apply band-aidsas we find other places with similar issues.)Back-patch to v12. v11 would also have the issue, except thatcommit920311a already applied a similar band-aid. That forcedexpansion in more cases than seem really necessary, though, sothis isn't a directly equivalent fix.Amit Langote, with some cosmetic changes by meDiscussion:https://postgr.es/m/16644-5da7ef98a7ac4545@postgresql.org
1 parente83c9f9 commitba9f18a

File tree

3 files changed

+90
-1
lines changed

3 files changed

+90
-1
lines changed

‎src/backend/commands/trigger.c

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,8 @@ static bool GetTupleForTrigger(EState *estate,
8989
LockTupleModelockmode,
9090
TupleTableSlot*oldslot,
9191
TupleTableSlot**newSlot);
92+
staticHeapTupleMaterializeTupleForTrigger(TupleTableSlot*slot,
93+
bool*shouldFree);
9294
staticboolTriggerEnabled(EState*estate,ResultRelInfo*relinfo,
9395
Trigger*trigger,TriggerEventevent,
9496
Bitmapset*modifiedCols,
@@ -2672,7 +2674,7 @@ ExecBRUpdateTriggers(EState *estate, EPQState *epqstate,
26722674
ExecCopySlot(newslot,epqslot_clean);
26732675
}
26742676

2675-
trigtuple=ExecFetchSlotHeapTuple(oldslot, true,&should_free_trig);
2677+
trigtuple=MaterializeTupleForTrigger(oldslot,&should_free_trig);
26762678
}
26772679
else
26782680
{
@@ -2925,6 +2927,9 @@ ExecASTruncateTriggers(EState *estate, ResultRelInfo *relinfo)
29252927
}
29262928

29272929

2930+
/*
2931+
* Fetch tuple into "oldslot", dealing with locking and EPQ if necessary
2932+
*/
29282933
staticbool
29292934
GetTupleForTrigger(EState*estate,
29302935
EPQState*epqstate,
@@ -3038,6 +3043,40 @@ GetTupleForTrigger(EState *estate,
30383043
return true;
30393044
}
30403045

3046+
/*
3047+
* Extract a HeapTuple that we can pass off to trigger functions.
3048+
*
3049+
* We must materialize the tuple and make sure it is not dependent on any
3050+
* attrmissing data. This is needed for the old row in BEFORE UPDATE
3051+
* triggers, since they can choose to pass back this exact tuple as the update
3052+
* result, causing the tuple to be inserted into an executor slot that lacks
3053+
* the attrmissing data.
3054+
*
3055+
* Currently we don't seem to need to remove the attrmissing dependency in any
3056+
* other cases, but keep this as a separate function to simplify fixing things
3057+
* if that changes.
3058+
*/
3059+
staticHeapTuple
3060+
MaterializeTupleForTrigger(TupleTableSlot*slot,bool*shouldFree)
3061+
{
3062+
HeapTupletup;
3063+
TupleDesctupdesc=slot->tts_tupleDescriptor;
3064+
3065+
tup=ExecFetchSlotHeapTuple(slot, true,shouldFree);
3066+
if (HeapTupleHeaderGetNatts(tup->t_data)<tupdesc->natts&&
3067+
tupdesc->constr&&tupdesc->constr->missing)
3068+
{
3069+
HeapTuplenewtup;
3070+
3071+
newtup=heap_expand_tuple(tup,tupdesc);
3072+
if (*shouldFree)
3073+
heap_freetuple(tup);
3074+
*shouldFree= true;
3075+
tup=newtup;
3076+
}
3077+
returntup;
3078+
}
3079+
30413080
/*
30423081
* Is trigger enabled to fire?
30433082
*/

‎src/test/regress/expected/triggers.out

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -214,6 +214,38 @@ select * from trigtest;
214214
----+----
215215
(0 rows)
216216

217+
drop table trigtest;
218+
-- Check behavior with an implicit column default, too (bug #16644)
219+
create table trigtest (a integer);
220+
create trigger trigger_return_old
221+
before insert or delete or update on trigtest
222+
for each row execute procedure trigger_return_old();
223+
insert into trigtest values(1);
224+
select * from trigtest;
225+
a
226+
---
227+
1
228+
(1 row)
229+
230+
alter table trigtest add column b integer default 42 not null;
231+
select * from trigtest;
232+
a | b
233+
---+----
234+
1 | 42
235+
(1 row)
236+
237+
update trigtest set a = 2 where a = 1 returning *;
238+
a | b
239+
---+----
240+
1 | 42
241+
(1 row)
242+
243+
select * from trigtest;
244+
a | b
245+
---+----
246+
1 | 42
247+
(1 row)
248+
217249
drop table trigtest;
218250
create sequence ttdummy_seq increment 10 start 0 minvalue 0;
219251
create table tttest (

‎src/test/regress/sql/triggers.sql

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,24 @@ select * from trigtest;
154154

155155
droptable trigtest;
156156

157+
-- Check behavior with an implicit column default, too (bug #16644)
158+
createtabletrigtest (ainteger);
159+
160+
createtriggertrigger_return_old
161+
before insertordeleteorupdateon trigtest
162+
for each row execute procedure trigger_return_old();
163+
164+
insert into trigtestvalues(1);
165+
select*from trigtest;
166+
167+
altertable trigtest add column binteger default42not null;
168+
169+
select*from trigtest;
170+
update trigtestset a=2where a=1 returning*;
171+
select*from trigtest;
172+
173+
droptable trigtest;
174+
157175
createsequencettdummy_seq increment10 start0 minvalue0;
158176

159177
createtabletttest (

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp