1 /*-------------------------------------------------------------------------
4 * Builtin functions for useful trigger support.
7 * Portions Copyright (c) 1996-2024, PostgreSQL Global Development Group
8 * Portions Copyright (c) 1994, Regents of the University of California
10 * src/backend/utils/adt/trigfuncs.c
12 *-------------------------------------------------------------------------
16 #include "access/htup_details.h"
17 #include "commands/trigger.h"
18 #include "utils/fmgrprotos.h"
22 * suppress_redundant_updates_trigger
24 * This trigger function will inhibit an update from being done
25 * if the OLD and NEW records are identical.
28 suppress_redundant_updates_trigger(PG_FUNCTION_ARGS
)
30 TriggerData
*trigdata
= (TriggerData
*) fcinfo
->context
;
34 HeapTupleHeader newheader
,
37 /* make sure it's called as a trigger */
38 if (!CALLED_AS_TRIGGER(fcinfo
))
40 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED
),
41 errmsg("suppress_redundant_updates_trigger: must be called as trigger")));
43 /* and that it's called on update */
44 if (!TRIGGER_FIRED_BY_UPDATE(trigdata
->tg_event
))
46 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED
),
47 errmsg("suppress_redundant_updates_trigger: must be called on update")));
49 /* and that it's called before update */
50 if (!TRIGGER_FIRED_BEFORE(trigdata
->tg_event
))
52 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED
),
53 errmsg("suppress_redundant_updates_trigger: must be called before update")));
55 /* and that it's called for each row */
56 if (!TRIGGER_FIRED_FOR_ROW(trigdata
->tg_event
))
58 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED
),
59 errmsg("suppress_redundant_updates_trigger: must be called for each row")));
61 /* get tuple data, set default result */
62 rettuple
= newtuple
= trigdata
->tg_newtuple
;
63 oldtuple
= trigdata
->tg_trigtuple
;
65 newheader
= newtuple
->t_data
;
66 oldheader
= oldtuple
->t_data
;
68 /* if the tuple payload is the same ... */
69 if (newtuple
->t_len
== oldtuple
->t_len
&&
70 newheader
->t_hoff
== oldheader
->t_hoff
&&
71 (HeapTupleHeaderGetNatts(newheader
) ==
72 HeapTupleHeaderGetNatts(oldheader
)) &&
73 ((newheader
->t_infomask
& ~HEAP_XACT_MASK
) ==
74 (oldheader
->t_infomask
& ~HEAP_XACT_MASK
)) &&
75 memcmp(((char *) newheader
) + SizeofHeapTupleHeader
,
76 ((char *) oldheader
) + SizeofHeapTupleHeader
,
77 newtuple
->t_len
- SizeofHeapTupleHeader
) == 0)
79 /* ... then suppress the update */
83 return PointerGetDatum(rettuple
);