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

Commit52120ee

Browse files
committed
Fix trigger WHEN conditions when both BEFORE and AFTER triggers exist.
Due to tuple-slot mismanagement, evaluation of WHEN conditions for AFTERROW UPDATE triggers could crash if there had been a BEFORE ROW triggerfired for the same update. Fix by not trying to overload the use ofestate->es_trig_tuple_slot. Per report from Yoran Heling.Back-patch to 9.0, when trigger WHEN conditions were introduced.
1 parent706493a commit52120ee

File tree

6 files changed

+67
-4
lines changed

6 files changed

+67
-4
lines changed

‎src/backend/commands/trigger.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2569,13 +2569,13 @@ TriggerEnabled(EState *estate, ResultRelInfo *relinfo,
25692569
}
25702570
if (HeapTupleIsValid(newtup))
25712571
{
2572-
if (estate->es_trig_tuple_slot==NULL)
2572+
if (estate->es_trig_newtup_slot==NULL)
25732573
{
25742574
oldContext=MemoryContextSwitchTo(estate->es_query_cxt);
2575-
estate->es_trig_tuple_slot=ExecInitExtraTupleSlot(estate);
2575+
estate->es_trig_newtup_slot=ExecInitExtraTupleSlot(estate);
25762576
MemoryContextSwitchTo(oldContext);
25772577
}
2578-
newslot=estate->es_trig_tuple_slot;
2578+
newslot=estate->es_trig_newtup_slot;
25792579
if (newslot->tts_tupleDescriptor!=tupdesc)
25802580
ExecSetSlotDescriptor(newslot,tupdesc);
25812581
ExecStoreTuple(newtup,newslot,InvalidBuffer, false);

‎src/backend/executor/execMain.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
790790
estate->es_tupleTable=NIL;
791791
estate->es_trig_tuple_slot=NULL;
792792
estate->es_trig_oldtup_slot=NULL;
793+
estate->es_trig_newtup_slot=NULL;
793794

794795
/* mark EvalPlanQual not active */
795796
estate->es_epqTuple=NULL;

‎src/backend/executor/execUtils.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ CreateExecutorState(void)
124124
estate->es_trig_target_relations=NIL;
125125
estate->es_trig_tuple_slot=NULL;
126126
estate->es_trig_oldtup_slot=NULL;
127+
estate->es_trig_newtup_slot=NULL;
127128

128129
estate->es_param_list_info=NULL;
129130
estate->es_param_exec_vals=NULL;

‎src/include/nodes/execnodes.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,7 @@ typedef struct EState
354354
/* Stuff used for firing triggers: */
355355
List*es_trig_target_relations;/* trigger-only ResultRelInfos */
356356
TupleTableSlot*es_trig_tuple_slot;/* for trigger output tuples */
357-
TupleTableSlot*es_trig_oldtup_slot;/* fortrigger old tuples */
357+
TupleTableSlot*es_trig_oldtup_slot;/* forTriggerEnabled */
358358

359359
/* Parameter info: */
360360
ParamListInfoes_param_list_info;/* values of external params */
@@ -397,6 +397,12 @@ typedef struct EState
397397
HeapTuple*es_epqTuple;/* array of EPQ substitute tuples */
398398
bool*es_epqTupleSet;/* true if EPQ tuple is provided */
399399
bool*es_epqScanDone;/* true if EPQ tuple has been fetched */
400+
401+
/*
402+
* this field added at end of struct to avoid post-release ABI breakage in
403+
* existing release branches. It'll be in a more logical place in 9.2.
404+
*/
405+
TupleTableSlot*es_trig_newtup_slot;/* for TriggerEnabled */
400406
}EState;
401407

402408

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -446,6 +446,35 @@ NOTICE: trigger_func(after_upd_a_b_row) called: action = UPDATE, when = AFTER,
446446
NOTICE: trigger_func(after_upd_b_row) called: action = UPDATE, when = AFTER, level = ROW
447447
NOTICE: trigger_func(after_upd_b_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
448448
NOTICE: trigger_func(after_upd_stmt) called: action = UPDATE, when = AFTER, level = STATEMENT
449+
--
450+
-- Test case for bug with BEFORE trigger followed by AFTER trigger with WHEN
451+
--
452+
CREATE TABLE some_t (some_col boolean NOT NULL);
453+
CREATE FUNCTION dummy_update_func() RETURNS trigger AS $$
454+
BEGIN
455+
RAISE NOTICE 'dummy_update_func(%) called: action = %, old = %, new = %',
456+
TG_ARGV[0], TG_OP, OLD, NEW;
457+
RETURN NEW;
458+
END;
459+
$$ LANGUAGE plpgsql;
460+
CREATE TRIGGER some_trig_before BEFORE UPDATE ON some_t FOR EACH ROW
461+
EXECUTE PROCEDURE dummy_update_func('before');
462+
CREATE TRIGGER some_trig_aftera AFTER UPDATE ON some_t FOR EACH ROW
463+
WHEN (NOT OLD.some_col AND NEW.some_col)
464+
EXECUTE PROCEDURE dummy_update_func('aftera');
465+
CREATE TRIGGER some_trig_afterb AFTER UPDATE ON some_t FOR EACH ROW
466+
WHEN (NOT NEW.some_col)
467+
EXECUTE PROCEDURE dummy_update_func('afterb');
468+
INSERT INTO some_t VALUES (TRUE);
469+
UPDATE some_t SET some_col = TRUE;
470+
NOTICE: dummy_update_func(before) called: action = UPDATE, old = (t), new = (t)
471+
UPDATE some_t SET some_col = FALSE;
472+
NOTICE: dummy_update_func(before) called: action = UPDATE, old = (t), new = (f)
473+
NOTICE: dummy_update_func(afterb) called: action = UPDATE, old = (t), new = (f)
474+
UPDATE some_t SET some_col = TRUE;
475+
NOTICE: dummy_update_func(before) called: action = UPDATE, old = (f), new = (t)
476+
NOTICE: dummy_update_func(aftera) called: action = UPDATE, old = (f), new = (t)
477+
DROP TABLE some_t;
449478
-- bogus cases
450479
CREATE TRIGGER error_upd_and_col BEFORE UPDATE OR UPDATE OF a ON main_table
451480
FOR EACH ROW EXECUTE PROCEDURE trigger_func('error_upd_and_col');

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

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,32 @@ SELECT pg_get_triggerdef(oid) FROM pg_trigger WHERE tgrelid = 'main_table'::regc
308308
UPDATE main_tableSET a=50;
309309
UPDATE main_tableSET b=10;
310310

311+
--
312+
-- Test case for bug with BEFORE trigger followed by AFTER trigger with WHEN
313+
--
314+
315+
CREATETABLEsome_t (some_colbooleanNOT NULL);
316+
CREATEFUNCTIONdummy_update_func() RETURNS triggerAS $$
317+
BEGIN
318+
RAISE NOTICE'dummy_update_func(%) called: action = %, old = %, new = %',
319+
TG_ARGV[0], TG_OP, OLD, NEW;
320+
RETURN NEW;
321+
END;
322+
$$ LANGUAGE plpgsql;
323+
CREATETRIGGERsome_trig_before BEFOREUPDATEON some_t FOR EACH ROW
324+
EXECUTE PROCEDURE dummy_update_func('before');
325+
CREATETRIGGERsome_trig_aftera AFTERUPDATEON some_t FOR EACH ROW
326+
WHEN (NOTOLD.some_colANDNEW.some_col)
327+
EXECUTE PROCEDURE dummy_update_func('aftera');
328+
CREATETRIGGERsome_trig_afterb AFTERUPDATEON some_t FOR EACH ROW
329+
WHEN (NOTNEW.some_col)
330+
EXECUTE PROCEDURE dummy_update_func('afterb');
331+
INSERT INTO some_tVALUES (TRUE);
332+
UPDATE some_tSET some_col= TRUE;
333+
UPDATE some_tSET some_col= FALSE;
334+
UPDATE some_tSET some_col= TRUE;
335+
DROPTABLE some_t;
336+
311337
-- bogus cases
312338
CREATETRIGGERerror_upd_and_col BEFOREUPDATEORUPDATE OF aON main_table
313339
FOR EACH ROW EXECUTE PROCEDURE trigger_func('error_upd_and_col');

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp