LCOV - code coverage report
Current view: top level - src/backend/utils/adt - trigfuncs.c (source / functions) Hit Total Coverage
Test: PostgreSQL Lines: 23 27 85.2 %
Date: 2017-09-29 13:40:31 Functions: 1 1 100.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*-------------------------------------------------------------------------
       2             :  *
       3             :  * trigfuncs.c
       4             :  *    Builtin functions for useful trigger support.
       5             :  *
       6             :  *
       7             :  * Portions Copyright (c) 1996-2017, PostgreSQL Global Development Group
       8             :  * Portions Copyright (c) 1994, Regents of the University of California
       9             :  *
      10             :  * src/backend/utils/adt/trigfuncs.c
      11             :  *
      12             :  *-------------------------------------------------------------------------
      13             :  */
      14             : #include "postgres.h"
      15             : 
      16             : #include "access/htup_details.h"
      17             : #include "commands/trigger.h"
      18             : #include "utils/builtins.h"
      19             : #include "utils/rel.h"
      20             : 
      21             : 
      22             : /*
      23             :  * suppress_redundant_updates_trigger
      24             :  *
      25             :  * This trigger function will inhibit an update from being done
      26             :  * if the OLD and NEW records are identical.
      27             :  */
      28             : Datum
      29          10 : suppress_redundant_updates_trigger(PG_FUNCTION_ARGS)
      30             : {
      31          10 :     TriggerData *trigdata = (TriggerData *) fcinfo->context;
      32             :     HeapTuple   newtuple,
      33             :                 oldtuple,
      34             :                 rettuple;
      35             :     HeapTupleHeader newheader,
      36             :                 oldheader;
      37             : 
      38             :     /* make sure it's called as a trigger */
      39          10 :     if (!CALLED_AS_TRIGGER(fcinfo))
      40           0 :         ereport(ERROR,
      41             :                 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
      42             :                  errmsg("suppress_redundant_updates_trigger: must be called as trigger")));
      43             : 
      44             :     /* and that it's called on update */
      45          10 :     if (!TRIGGER_FIRED_BY_UPDATE(trigdata->tg_event))
      46           0 :         ereport(ERROR,
      47             :                 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
      48             :                  errmsg("suppress_redundant_updates_trigger: must be called on update")));
      49             : 
      50             :     /* and that it's called before update */
      51          10 :     if (!TRIGGER_FIRED_BEFORE(trigdata->tg_event))
      52           0 :         ereport(ERROR,
      53             :                 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
      54             :                  errmsg("suppress_redundant_updates_trigger: must be called before update")));
      55             : 
      56             :     /* and that it's called for each row */
      57          10 :     if (!TRIGGER_FIRED_FOR_ROW(trigdata->tg_event))
      58           0 :         ereport(ERROR,
      59             :                 (errcode(ERRCODE_E_R_I_E_TRIGGER_PROTOCOL_VIOLATED),
      60             :                  errmsg("suppress_redundant_updates_trigger: must be called for each row")));
      61             : 
      62             :     /* get tuple data, set default result */
      63          10 :     rettuple = newtuple = trigdata->tg_newtuple;
      64          10 :     oldtuple = trigdata->tg_trigtuple;
      65             : 
      66          10 :     newheader = newtuple->t_data;
      67          10 :     oldheader = oldtuple->t_data;
      68             : 
      69             :     /*
      70             :      * We are called before the OID, if any, has been transcribed from the old
      71             :      * tuple to the new (in heap_update).  To avoid a bogus compare failure,
      72             :      * copy the OID now.  But check that someone didn't already put another
      73             :      * OID value into newtuple.  (That's not actually possible at present, but
      74             :      * maybe someday.)
      75             :      */
      76          15 :     if (trigdata->tg_relation->rd_rel->relhasoids &&
      77          10 :         !OidIsValid(HeapTupleHeaderGetOid(newheader)))
      78           5 :         HeapTupleHeaderSetOid(newheader, HeapTupleHeaderGetOid(oldheader));
      79             : 
      80             :     /* if the tuple payload is the same ... */
      81          18 :     if (newtuple->t_len == oldtuple->t_len &&
      82          16 :         newheader->t_hoff == oldheader->t_hoff &&
      83          16 :         (HeapTupleHeaderGetNatts(newheader) ==
      84          16 :          HeapTupleHeaderGetNatts(oldheader)) &&
      85          16 :         ((newheader->t_infomask & ~HEAP_XACT_MASK) ==
      86          16 :          (oldheader->t_infomask & ~HEAP_XACT_MASK)) &&
      87           8 :         memcmp(((char *) newheader) + SizeofHeapTupleHeader,
      88             :                ((char *) oldheader) + SizeofHeapTupleHeader,
      89           8 :                newtuple->t_len - SizeofHeapTupleHeader) == 0)
      90             :     {
      91             :         /* ... then suppress the update */
      92           4 :         rettuple = NULL;
      93             :     }
      94             : 
      95          10 :     return PointerGetDatum(rettuple);
      96             : }

Generated by: LCOV version 1.11