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 iSeries.
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);
}
}