A simple RPG ILE Trigger Program
This morning, an old programming chum of mine was chatting to me about writing a program, that would be called every time anything was updated in a given file (table) on the system. This action is very simple in the IBM-i world, using a technique called FILE TRIGGERS.
What is a Trigger?
A trigger is a program that is called whenever a row of data is updated, added or deleted. It has a generic input in the form of (a) a data structure holding various codes and also the the record that was updated and (b) the size of the data that was changed in (a).
So I dug out this old trigger (that I copied from somewhere a couple of years back) and just ran through my RPGLE Modernizer routine:
**FREE
//
// Skeleton trigger program using RPGLE V7.1+
//
ctl-opt
copyright('| @SKELTRIG V001 2017.04.19')
debug option(*nodebugio: *srcstmt)
datfmt(*iso-) timfmt(*iso.)
indent('| ');
dcl-pi *n;
Trgbuffer likeds(trigger);
Trgbufferlen int(10);
end-pi;
// Possible values for Event
dcl-c Insert '1';
dcl-c Delete '2';
dcl-c Update '3';
dcl-c Read '4';
// Possible values for Time
dcl-c After '1';
dcl-c Before '2';
// Possible values for Commitlocklev
dcl-c Cmtnone '0';
dcl-c Cmtchange '1';
dcl-c Cmtcs '2';
dcl-c Cmtall '3';
// Trigger buffer information
dcl-ds trigger qualified;
File char(10);
Library char(10);
Member char(10);
Event char(1);
Time char(1);
Commitlocklev char(1);
*n char(3);
Ccsid int(10);
Rrn int(10);
*n char(4);
Befrecoffset int(10);
Befreclen int(10);
Befnulloffset int(10);
Befnulllen int(10);
Aftrecoffset int(10);
Aftreclen int(10);
Aftnulloffset int(10);
Aftnulllen int(10);
end-ds;
// "Before" record image
dcl-s Befrecptr pointer;
dcl-ds Old extname('MYFILE') based(befrecptr) qualified end-ds;
// "After" record image
dcl-s Aftrecptr pointer;
dcl-ds New extname('MYFILE') based(aftrecptr) qualified end-ds;
// Map trigger buffer into data structures
Befrecptr = %ADDR(Trgbuffer) + Trgbuffer.Befrecoffset;
Aftrecptr = %ADDR(Trgbuffer) + Trgbuffer.Aftrecoffset;
// Trigger processing goes here
// Refer to Old field names with "old." qualification
// Refer to new field names with "new." qualification
select;
when trgbuffer.event = Insert;
// add some logic here for Insert processing
// for example, something like this:
if old.address <> new.address;
// write some audit report detailing customers changed of address
endif;
when trgbuffer.event = Delete;
// add some logic here for Delete processing
when trgbuffer.event = Update;
// add some logic here for Update processing
when trgbuffer.event = Read;
// add some logic here for Read processing
endsl;
Return;
Hope this works for ya! 🙂
Hello Nick,
My name is Antonio Mira. I am now working for AHP (Bob Wilson) and have come across some of your programs. I like your website. It has helped me immensely in my job so thank you for that. After a few years of not programming in the i now I’m back in it and rediscovering my love for the i and RPG. I do have a question for you. So, I’m trying to do is to call a program that accepts a data structure as a parameter. I can do that with no problem calling the program directly but what I want to do is submit that program. I just don’t know how I would do that with QCMDEXC being that the program is expecting a DS. Would I have to build the call string with all the parameters, one by one? The program that I’m calling is a report that I want to submit.
This is what I have: (at the top of report prompt screen where the user enters report criteria)
//DS for parameters for the report
dcl-ds rptCriteriaDS qualified;
@fromDate70 packed(7:0);
@toDate70 packed(7:0);
$XMIT char(1);
$CRDSTS char(1);
end-ds;
//prototype to call AI5007RP Credit Audit History report
dcl-pr creditAudHistRpt extpgm(‘AI5007RP’);
parmDS likeDS(rptCriteriaDS);
end-pr;
Then, I simply call the report later on:
//populate the DS
creditAudHistRpt(rptCriteriaDS);
So the question is how do I submit this report? Thank you for any advice you can provide.
Hey Nick, thanks for the example. Very helpful, very clean. Can you check one thing? Where you have trigger.insert, trigger.whatever. That should be trgBuffer.whatever, right? I changed my code to use trgBuffer.
You are absolutely correct Pat! I’ve updated the example. #nicecatch
Not to be horribly picky, but a ‘*’ is needed before ‘srcstmt’ on the debug option line at the beginning of code
Thanks Jim, WordPress converts asterisks when copying/pasting code samples. I missed this one. I’ve updated the code example – thanks for the headsup!
Thanks Nick, the example is quite practical, I copied it, compiled it and run ok, there is a person in Smc, Silao Mexico, with an FTP problem which we have not been able to solve, I attached his email in case you can help him
Rocio Calzada Rubio rcalzada@smcmx.com.mx
Dew Causeway
Administrative Direction
SMC Corporation Mexico, S.A. of C.V.
Telephone 472 7225500 Ext. 2032
Thanks in advance this is my email
rodolfo.rodriguez@janel.com
rorocaro-@live.com.mx
Merci Nick, the example is very practical, I copied it, compiled it and run ok.
However I have a small issue with the trigger buffer information DS (Trigger), it is not initialized, not sure what I missed. Thanks
Forgive me Nick ! I found it ! After a good coffee ! 🙂
como capturo el nombre del programa en desde onde se hace la actualización y la IP desde donde se ejecuta??
Hi Nick,
I have a trigger pgm that will be used in Test and Production environments. How can the trigger be setup to use a JOBD that sets the correct liblist? Or how can the CL determine what library the CL was called from? I tried to use RTVJOBA, but when we update a triggered file using SQL scripts, the *CURLIB value is *NONE.
Thanks for this clean sample of a trigger program! Very helpful.
Setting *iNLR to *ON is deadly on an active table, performance will suck.
what’s the difference between trigger and journal? seems both them can record the values updates