|
| 1 | +/*------------------------------------------------------------------------- |
| 2 | + * |
| 3 | + * trigfuncs.c |
| 4 | + * Builtin functions for useful trigger support. |
| 5 | + * |
| 6 | + * |
| 7 | + * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group |
| 8 | + * Portions Copyright (c) 1994, Regents of the University of California |
| 9 | + * |
| 10 | + * $PostgreSQL: pgsql/src/backend/utils/adt/trigfuncs.c,v 1.1 2008/11/03 20:17:20 adunstan Exp $ |
| 11 | + * |
| 12 | + *------------------------------------------------------------------------- |
| 13 | + */ |
| 14 | + |
| 15 | + |
| 16 | + |
| 17 | +#include "postgres.h" |
| 18 | +#include "commands/trigger.h" |
| 19 | +#include "access/htup.h" |
| 20 | + |
| 21 | +/* |
| 22 | + * suppress_redundant_updates_trigger |
| 23 | + * |
| 24 | + * This trigger function will inhibit an update from being done |
| 25 | + * if the OLD and NEW records are identical. |
| 26 | + * |
| 27 | + */ |
| 28 | + |
| 29 | +Datum |
| 30 | +suppress_redundant_updates_trigger(PG_FUNCTION_ARGS) |
| 31 | +{ |
| 32 | + TriggerData *trigdata = (TriggerData *) fcinfo->context; |
| 33 | + HeapTuple newtuple, oldtuple, rettuple; |
| 34 | + HeapTupleHeader newheader, oldheader; |
| 35 | + |
| 36 | + /* make sure it's called as a trigger */ |
| 37 | + if (!CALLED_AS_TRIGGER(fcinfo)) |
| 38 | + elog(ERROR, (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), |
| 39 | + errmsg("suppress_redundant_updates_trigger: must be called as trigger"))); |
| 40 | + |
| 41 | + /* and that it's called on update */ |
| 42 | + if (! TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event)) |
| 43 | + ereport(ERROR, (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), |
| 44 | + errmsg( "suppress_redundant_updates_trigger: may only be called on update"))); |
| 45 | + |
| 46 | + /* and that it's called before update */ |
| 47 | + if (! TRIGGER_FIRED_BEFORE(trigdata->tg_event)) |
| 48 | + ereport(ERROR, (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), |
| 49 | + errmsg( "suppress_redundant_updates_trigger: may only be called before update"))); |
| 50 | + |
| 51 | + /* and that it's called for each row */ |
| 52 | + if (! TRIGGER_FIRED_FOR_ROW(trigdata->tg_event)) |
| 53 | + ereport(ERROR, (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED), |
| 54 | + errmsg( "suppress_redundant_updates_trigger: may only be called for each row"))); |
| 55 | + |
| 56 | + /* get tuple data, set default return */ |
| 57 | + rettuple = newtuple = trigdata->tg_newtuple; |
| 58 | + oldtuple = trigdata->tg_trigtuple; |
| 59 | + |
| 60 | + newheader = newtuple->t_data; |
| 61 | + oldheader = oldtuple->t_data; |
| 62 | + |
| 63 | + if (newtuple->t_len == oldtuple->t_len && |
| 64 | + newheader->t_hoff == oldheader->t_hoff && |
| 65 | + (HeapTupleHeaderGetNatts(newheader) == |
| 66 | + HeapTupleHeaderGetNatts(oldheader) ) && |
| 67 | + ((newheader->t_infomask & ~HEAP_XACT_MASK) == |
| 68 | + (oldheader->t_infomask & ~HEAP_XACT_MASK) )&& |
| 69 | + memcmp(((char *)newheader) + offsetof(HeapTupleHeaderData, t_bits), |
| 70 | + ((char *)oldheader) + offsetof(HeapTupleHeaderData, t_bits), |
| 71 | + newtuple->t_len - offsetof(HeapTupleHeaderData, t_bits)) == 0) |
| 72 | + { |
| 73 | + rettuple = NULL; |
| 74 | + } |
| 75 | + |
| 76 | + return PointerGetDatum(rettuple); |
| 77 | +} |
0 commit comments