April 22

13 comments

Example RPG ILE Trigger Program

By NickLitten

April 22, 2017

snippet, RPGLE, skeleton, trigger

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.

  • Not to be horribly picky, but a ‘*’ is needed before ‘srcstmt’ on the debug option line at the beginning of code

  • 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

  • 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.

  • {"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}

    Join the IBM i Community for FREE Presentations, Lessons, Hints and Tips

    >