Example: Trigger program

This example shows an external trigger program that is written in ILE C with embedded SQL.

For more trigger program examples, see the IBM® Redbooks® publication Stored Procedures, Triggers, and User-Defined Functions on DB2 Universal Database for iSeriesLink to PDF.

Note: By using the code examples, you agree to the terms of the Code license and disclaimer information.
#include "string.h"
#include "stdlib.h"
#include "stdio.h"
#include <recio.h>
#include <xxcvt.h>
#include "qsysinc/h/trgbuf"       /* Trigger input parameter         */
#include "lib1/csrc/msghand1"     /* User defined message handler    */
/*********************************************************************/
/* This is a trigger program which is called whenever there is an    */
/* update to the EMPLOYEE table. If the employee's commission is     */
/* greater than the maximum commission, this trigger program will    */
/* increase the employee's salary by 1.04 percent and insert into    */
/* the RAISE table.                                                  */
/*                                                                   */
/* The EMPLOYEE record information is passed from the input parameter*/
/* to this trigger program.                                          */
/*********************************************************************/
 
Qdb_Trigger_Buffer_t *hstruct;
char *datapt;
 
   /*******************************************************/
   /* Structure of the EMPLOYEE record which is used to   */
   /* store the old or the new record that is passed to   */
   /* this trigger program.                               */
   /*                                                     */
   /* Note : You must ensure that all the numeric fields  */
   /*        are aligned at 4 byte boundary in C.         */
   /*        Used either Packed struct or filler to reach */
   /*        the byte boundary alignment.                 */
   /*******************************************************/
 
_Packed struct rec{
         char  empn[6];
  _Packed struct { short fstlen ;
                  char  fstnam[12];
                } fstname;
         char  minit[1];
_Packed struct { short lstlen;
                char lstnam[15];
              } lstname;
       char  dept[3];
       char  phone[4];
       char  hdate[10];
       char  jobn[8];
       short edclvl;
       char  sex1[1];
       char  bdate[10];
       decimal(9,2) salary1;
       decimal(9,2) bonus1;
       decimal(9,2) comm1;
       } oldbuf, newbuf;
EXEC SQL INCLUDE SQLCA;
main(int argc, char **argv)
{
int i;
int obufoff;                       /* old buffer offset            */
int nuloff;                        /* old null byte map offset     */
int nbufoff;                       /* new buffer offset            */
int nul2off;                       /* new null byte map offset     */
short work_days  = 253;            /* work days during in one year */
decimal(9,2) commission = 2000.00; /* cutoff to qualify for        */
decimal(9,2) percentage = 1.04;    /* raised salary as percentage  */
char raise_date[12] = "1982-06-01";/* effective raise date         */
 
 
struct {
       char  empno[6];
       char  name[30];
       decimal(9,2) salary;
       decimal(9,2) new_salary;
       } rpt1;
 
   /*******************************************************/
   /* Start to monitor any exception.                     */
   /*******************************************************/
 
  _FEEDBACK fc;
  _HDLR_ENTRY hdlr = main_handler;
                             /****************************************/
                             /* Make the exception handler active.   */
                             /****************************************/
  CEEHDLR(&hdlr, NULL, &fc);
                             /****************************************/
                             /* Ensure exception handler OK          */
                             /****************************************/
  if (fc.MsgNo != CEE0000)
    {
      printf("Failed to register exception handler.\n");
      exit(99);
    };
 
   /*******************************************************/
   /* Move the data from the trigger buffer to the local  */
   /* structure for reference.                            */
   /*******************************************************/
 
hstruct = (Qdb_Trigger_Buffer_t *)argv[1];
datapt  = (char *) hstruct;
 
obufoff = hstruct ->Old_Record_Offset;       /* old buffer   */
memcpy(&oldbuf,datapt+obufoff,; hstruct->Old_Record_Len);
 
nbufoff = hstruct ->New_Record_Offset;       /* new buffer   */
memcpy(&newbuf,datapt+nbufoff,; hstruct->New_Record_Len);
EXEC SQL WHENEVER SQLERROR  GO TO ERR_EXIT;
 
   /*******************************************************/
   /* Set the transaction isolation level to the same as  */
   /* the application based on the input parameter in the */
   /* trigger buffer.                                     */
   /*******************************************************/
 
if(strcmp(hstruct->Commit_Lock_Level,"0") == 0)
     EXEC SQL SET TRANSACTION ISOLATION LEVEL NONE;
else{
  if(strcmp(hstruct->Commit_Lock_Level,"1") == 0)
       EXEC SQL SET TRANSACTION ISOLATION LEVEL READ UNCOMMITTED, READ
                 WRITE;
  else {
     if(strcmp(hstruct->Commit_Lock_Level,"2") == 0)
       EXEC SQL SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
  else
     if(strcmp(hstruct->Commit_Lock_Level,"3") == 0)
       EXEC SQL SET TRANSACTION ISOLATION LEVEL ALL;
  }
}
 
 /********************************************************/
 /* If the employee's commission is greater than maximum */
 /* commission, then increase the employee's salary      */
 /* by 1.04 percent and insert into the RAISE table.     */
 /********************************************************/
 
if (newbuf.comm1 >= commission)
{
  EXEC SQL  SELECT EMPNO, EMPNAME, SALARY
         INTO :rpt1.empno, :rpt1.name, :rpt1.salary
         FROM TRGPERF/EMP_ACT
         WHERE EMP_ACT.EMPNO=:newbuf.empn ;
 
  if (sqlca.sqlcode == 0) then
  {
     rpt1.new_salary = salary * percentage;
     EXEC SQL INSERT INTO TRGPERF/RAISE VALUES(:rpt1);
  }
  goto finished;
 }
 err_exit:
   exit(1);
 
  /* All done  */
 finished:
  return;
}  /* end of main line  */
 
/******************************************************************/
/*   INCLUDE NAME : MSGHAND1                                      */
/*                                                                */
/*   DESCRIPTION  : Message handler to signal an exception to     */
/*                  the application to inform that an             */
/*                  error occured in the trigger program.         */
/*                                                                */
/*   NOTE : This message handler is a user defined routine.       */
/*                                                                */
/******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <recio.h>
#include <leawi.h>
 
#pragma linkage (QMHSNDPM, OS)
void QMHSNDPM(char *,             /* Message identifier             */
              void *,             /* Qualified message file name    */
              void *,             /* Message data or text           */
              int,                /* Length of message data or text */
              char *,             /* Message type                   */
              char *,             /* Call message queue             */
              int,                /* Call stack counter             */
              void *,             /* Message key                    */
              void *,             /* Error code                     */
              ...);               /* Optionals:
                                       length of call message queue
                                        name
                                       Call stack entry qualification
                                       display external messages
                                        screen wait time            */
/*********************************************************************/
/********  This is the start of the exception handler function.      */
/*********************************************************************/
  void main_handler(_FEEDBACK *cond, _POINTER *token, _INT4 *rc,
                    _FEEDBACK *new)
   {
                            /****************************************/
                            /* Initialize variables for call to     */
                            /* QMHSNDPM.                            */
                            /* User must create a message file and  */
                            /* define a message ID to match the     */
                            /* following data.                      */
                            /****************************************/
  char      message_id[7] = "TRG9999";
  char      message_file[20] = "MSGF      LIB1      ";
  char      message_data[50] = "Trigger error                 " ;
  int       message_len = 30;
  char      message_type[10] = "*ESCAPE   ";
  char      message_q[10] = "_C_pep    ";
  int       pgm_stack_cnt = 1;
  char      message_key[4];
                            /****************************************/
                            /* Declare error code structure for     */
                            /* QMHSNDPM.                            */
                            /****************************************/
struct error_code {
  int bytes_provided;
  int bytes_available;
  char message_id[7];
} error_code;
 
error_code.bytes_provided = 15;
                            /****************************************/
                            /* Set the error handler to resume and  */
                            /* mark the last escape message as      */
                            /* handled.                             */
                            /****************************************/
*rc = CEE_HDLR_RESUME;
                            /****************************************/
                            /* Send my own *ESCAPE message.         */
                            /****************************************/
QMHSNDPM(message_id,
        &message_file,
        &message_data,
         message_len,
         message_type,
         message_q,
         pgm_stack_cnt,
        &message_key,
        &error_code );
                            /****************************************/
                            /* Check that the call to QMHSNDPM      */
                            /* finished correctly.                  */
                            /****************************************/
if (error_code.bytes_available != 0)
    {
      printf("Error in QMHOVPM : %s\n", error_code.message_id);
    }
}