Header And Logo

PostgreSQL
| The world's most advanced open source database.

trigfuncs.c

Go to the documentation of this file.
00001 /*-------------------------------------------------------------------------
00002  *
00003  * trigfuncs.c
00004  *    Builtin functions for useful trigger support.
00005  *
00006  *
00007  * Portions Copyright (c) 1996-2013, PostgreSQL Global Development Group
00008  * Portions Copyright (c) 1994, Regents of the University of California
00009  *
00010  * src/backend/utils/adt/trigfuncs.c
00011  *
00012  *-------------------------------------------------------------------------
00013  */
00014 #include "postgres.h"
00015 
00016 #include "access/htup_details.h"
00017 #include "commands/trigger.h"
00018 #include "utils/builtins.h"
00019 #include "utils/rel.h"
00020 
00021 
00022 /*
00023  * suppress_redundant_updates_trigger
00024  *
00025  * This trigger function will inhibit an update from being done
00026  * if the OLD and NEW records are identical.
00027  */
00028 Datum
00029 suppress_redundant_updates_trigger(PG_FUNCTION_ARGS)
00030 {
00031     TriggerData *trigdata = (TriggerData *) fcinfo->context;
00032     HeapTuple   newtuple,
00033                 oldtuple,
00034                 rettuple;
00035     HeapTupleHeader newheader,
00036                 oldheader;
00037 
00038     /* make sure it's called as a trigger */
00039     if (!CALLED_AS_TRIGGER(fcinfo))
00040         ereport(ERROR,
00041                 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
00042                  errmsg("suppress_redundant_updates_trigger: must be called as trigger")));
00043 
00044     /* and that it's called on update */
00045     if (!TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
00046         ereport(ERROR,
00047                 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
00048                  errmsg("suppress_redundant_updates_trigger: must be called on update")));
00049 
00050     /* and that it's called before update */
00051     if (!TRIGGER_FIRED_BEFORE(trigdata->tg_event))
00052         ereport(ERROR,
00053                 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
00054                  errmsg("suppress_redundant_updates_trigger: must be called before update")));
00055 
00056     /* and that it's called for each row */
00057     if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
00058         ereport(ERROR,
00059                 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
00060                  errmsg("suppress_redundant_updates_trigger: must be called for each row")));
00061 
00062     /* get tuple data, set default result */
00063     rettuple = newtuple = trigdata->tg_newtuple;
00064     oldtuple = trigdata->tg_trigtuple;
00065 
00066     newheader = newtuple->t_data;
00067     oldheader = oldtuple->t_data;
00068 
00069     /*
00070      * We are called before the OID, if any, has been transcribed from the old
00071      * tuple to the new (in heap_update).  To avoid a bogus compare failure,
00072      * copy the OID now.  But check that someone didn't already put another
00073      * OID value into newtuple.  (That's not actually possible at present, but
00074      * maybe someday.)
00075      */
00076     if (trigdata->tg_relation->rd_rel->relhasoids &&
00077         !OidIsValid(HeapTupleHeaderGetOid(newheader)))
00078         HeapTupleHeaderSetOid(newheader, HeapTupleHeaderGetOid(oldheader));
00079 
00080     /* if the tuple payload is the same ... */
00081     if (newtuple->t_len == oldtuple->t_len &&
00082         newheader->t_hoff == oldheader->t_hoff &&
00083         (HeapTupleHeaderGetNatts(newheader) ==
00084          HeapTupleHeaderGetNatts(oldheader)) &&
00085         ((newheader->t_infomask & ~HEAP_XACT_MASK) ==
00086          (oldheader->t_infomask & ~HEAP_XACT_MASK)) &&
00087         memcmp(((char *) newheader) + offsetof(HeapTupleHeaderData, t_bits),
00088                ((char *) oldheader) + offsetof(HeapTupleHeaderData, t_bits),
00089                newtuple->t_len - offsetof(HeapTupleHeaderData, t_bits)) == 0)
00090     {
00091         /* ... then suppress the update */
00092         rettuple = NULL;
00093     }
00094 
00095     return PointerGetDatum(rettuple);
00096 }