38.3. Writing Trigger Functions in C
This section describes the low-level details of the interface to a trigger function. This information is only needed when writing trigger functions in C. If you are using a higher-level language then these details are handled for you. In most cases you should consider using a procedural language before writing your triggers in C. The documentation of each procedural language explains how to write a trigger in that language.
Trigger functions must use the " version 1 " function manager interface.
  When a function is called by the trigger manager, it is not passed
    any normal arguments, but it is passed a
  
   "
   
    context
   
   "
  
  pointer pointing to a
  
   TriggerData
  
  structure.  C
    functions can check whether they were called from the trigger
    manager or not by executing the macro:
 
CALLED_AS_TRIGGER(fcinfo)
which expands to:
((fcinfo)->context != NULL && IsA((fcinfo)->context, TriggerData))
  If this returns true, then it is safe to cast
  
   fcinfo->context
  
  to type
  
   TriggerData
    *
  
  and make use of the pointed-to
  
   TriggerData
  
  structure.  The function must
  
   
    not
   
  
  alter the
  
   TriggerData
  
  structure or any of the data it points to.
 
  
   struct TriggerData
  
  is defined in
  
   commands/trigger.h
  
  :
 
typedef struct TriggerData
{
    NodeTag          type;
    TriggerEvent     tg_event;
    Relation         tg_relation;
    HeapTuple        tg_trigtuple;
    HeapTuple        tg_newtuple;
    Trigger         *tg_trigger;
    TupleTableSlot  *tg_trigslot;
    TupleTableSlot  *tg_newslot;
    Tuplestorestate *tg_oldtable;
    Tuplestorestate *tg_newtable;
} TriggerData;
 where the members are defined as follows:
- 
    
     type
- 
    Always T_TriggerData.
- 
    
     tg_event
- 
    Describes the event for which the function is called. You can use the following macros to examine tg_event:- 
       
        TRIGGER_FIRED_BEFORE(tg_event)
- 
       Returns true if the trigger fired before the operation. 
- 
       
        TRIGGER_FIRED_AFTER(tg_event)
- 
       Returns true if the trigger fired after the operation. 
- 
       
        TRIGGER_FIRED_INSTEAD(tg_event)
- 
       Returns true if the trigger fired instead of the operation. 
- 
       
        TRIGGER_FIRED_FOR_ROW(tg_event)
- 
       Returns true if the trigger fired for a row-level event. 
- 
       
        TRIGGER_FIRED_FOR_STATEMENT(tg_event)
- 
       Returns true if the trigger fired for a statement-level event. 
- 
       
        TRIGGER_FIRED_BY_INSERT(tg_event)
- 
       Returns true if the trigger was fired by an INSERTcommand.
- 
       
        TRIGGER_FIRED_BY_UPDATE(tg_event)
- 
       Returns true if the trigger was fired by an UPDATEcommand.
- 
       
        TRIGGER_FIRED_BY_DELETE(tg_event)
- 
       Returns true if the trigger was fired by a DELETEcommand.
- 
       
        TRIGGER_FIRED_BY_TRUNCATE(tg_event)
- 
       Returns true if the trigger was fired by a TRUNCATEcommand.
 
- 
       
        
- 
    
     tg_relation
- 
    A pointer to a structure describing the relation that the trigger fired for. Look at utils/rel.hfor details about this structure. The most interesting things aretg_relation->rd_att(descriptor of the relation tuples) andtg_relation->rd_rel->relname(relation name; the type is notchar*butNameData; useSPI_getrelname(tg_relation)to get achar*if you need a copy of the name).
- 
    
     tg_trigtuple
- 
    A pointer to the row for which the trigger was fired. This is the row being inserted, updated, or deleted. If this trigger was fired for an INSERTorDELETEthen this is what you should return from the function if you don't want to replace the row with a different one (in the case ofINSERT) or skip the operation. For triggers on foreign tables, values of system columns herein are unspecified.
- 
    
     tg_newtuple
- 
    A pointer to the new version of the row, if the trigger was fired for an UPDATE, andNULLif it is for anINSERTor aDELETE. This is what you have to return from the function if the event is anUPDATEand you don't want to replace this row by a different one or skip the operation. For triggers on foreign tables, values of system columns herein are unspecified.
- 
    
     tg_trigger
- 
    A pointer to a structure of type Trigger, defined inutils/reltrigger.h:typedef struct Trigger { Oid tgoid; char *tgname; Oid tgfoid; int16 tgtype; char tgenabled; bool tgisinternal; Oid tgconstrrelid; Oid tgconstrindid; Oid tgconstraint; bool tgdeferrable; bool tginitdeferred; int16 tgnargs; int16 tgnattr; int16 *tgattr; char **tgargs; char *tgqual; char *tgoldtable; char *tgnewtable; } Trigger;where tgnameis the trigger's name,tgnargsis the number of arguments intgargs, andtgargsis an array of pointers to the arguments specified in theCREATE TRIGGERstatement. The other members are for internal use only.
- 
    
     tg_trigslot
- 
    The slot containing tg_trigtuple, or aNULLpointer if there is no such tuple.
- 
    
     tg_newslot
- 
    The slot containing tg_newtuple, or aNULLpointer if there is no such tuple.
- 
    
     tg_oldtable
- 
    A pointer to a structure of type Tuplestorestatecontaining zero or more rows in the format specified bytg_relation, or aNULLpointer if there is noOLD TABLEtransition relation.
- 
    
     tg_newtable
- 
    A pointer to a structure of type Tuplestorestatecontaining zero or more rows in the format specified bytg_relation, or aNULLpointer if there is noNEW TABLEtransition relation.
To allow queries issued through SPI to reference transition tables, see SPI_register_trigger_data .
  A trigger function must return either a
  
   HeapTuple
  
  pointer or a
  
   NULL
  
  pointer
    (
  
   
    not
   
  
  an SQL null value, that is, do not set
  
   
    isNull
   
  
  true).
    Be careful to return either
  
   tg_trigtuple
  
  or
  
   tg_newtuple
  
  ,
    as appropriate, if you don't want to modify the row being operated on.