Back to Tylogix Home Page

Trigger Techniques on the AS/400

Trigger Tips
IBM Manual: Stored Procedures, Triggers and User Defined Functions on DB2 Universal Database for iSeries


By Thibault Dambrine

Doing the same thing over and over again tends to breed boredom and mistakes. This is true for every profession. For our benefit, the AS/400 operating system is taking one more step to make our programming life more fruitful and possibly less repetitive. Triggers is the subject of this article. This is a new feature on the AS/400. It is a simple concept and it can be applied in a lot of situations where data checks and edits are repeated from one program to another. As time goes by, databases grow. The working life of the average programmer is divided into two halves:

Half Number One: We create data models to store and organize data in space-efficient and logically organized ways.

Half Number Two: We write programs to maintain this data, while following rules we created in the first half (as best we can). This is where DB2/400 Triggers fit in.

What are DB2/400 Triggers and What Do They Do?

A trigger is an action, or set of actions that are invoked automatically when a specified operation is performed on a specified physical file. The operation can be an insert, an update, or a delete instruction in a high level language statement in an application program. The action is executed by a user-written program. Database users can use triggers to: validate input data; query from other files for cross referencing purposes; enforce business rules; access system functions (for example, print an exception message when a rule is violated); replicate data to different files to achieve data consistency, and write to other files for audit trail purposes.

Benefits of Triggers

The following benefits can be realized in customersí business environments:

Faster application development: Because triggers are stored in the database, the actions performed by triggers do not have to be coded in each HLL application.

Global enforcement of business rules: A trigger can to be defined once and then reused for any application using the database.

Maintenance savings: If a business policy changes, it is necessary to change only the trigger program linked to a database file instead of every application program that touches it.

Improved performance in client/server environment: Triggers can be used in client/server situations where one IO from the client can in fact trigger multiple actions at the server level, thus freeing the wire between the Client and the Server for other transactions.

Automated enforcement of complex business rules: Triggers can stand alone, or can also be used in conjunction with commitment control and with referential integrity. With these tools, one could potentially make business rules practically self-enforcing; regardless of the application that touches the data.

How to Define a Trigger

There are three basic components of a DB2/400 Trigger. The first is a physical file to which the trigger will be linked. The second is a trigger event definition, which is the action that will set off or "pull" the trigger. This can be an add, update or delete record within the chosen physical file. Finally there must be a trigger time definition, the time at which the trigger will be "pulled". This can be before the event, after the event, or both. You can associate a maximum of six triggers to one physical file, one for each of the following situations: before an insert; after an insert; before a delete; after a delete; before an update; and, after an update.

A trigger program will be literally called as a result of the trigger being "pulled". It will be in a position to receive information about the record to be added or updated in the physical file to monitor and it will take action based on that data. This can mean to perform a number of other database actions (such as other writes) or a check from one file to an other which can result in success or failure. The failure will be detected by the operating system. The trigger program is user-written. It can be written in any high-level language currently available on the AS/400.

Adding, Removing and Displaying a Trigger

A trigger is added to a physical file using the Add Physical File Trigger (ADDPFTRG) command. Once the association exists between a file and a trigger program, the system calls the trigger program when a data operation is initiated against the physical file, any member of the physical file, and any logical file created over the physical file.

The Remove Physical File Trigger (RMVPFTRG) command removes the association of file with its trigger program. Once you remove this association, no action is taken if a change is made to the physical file. The trigger program, however, remains on the system.

To display the components of a trigger, simply use the Display File Description (DSPFD) command. It provides a list of the triggers associated with a file. Specify TYPE(*TRG) or TYPE(*ALL) to get this list. The information provided is:

The number of trigger programs (note that there can be up to 6 per file - one per action)

The trigger program names and libraries

The trigger events

The trigger times

The trigger update conditions

The firing of one trigger program can cause another trigger which can cause an avalanche of nested triggers, recursive triggers and potentially looping triggers. Infinite loops are possible in this scenario. Careful planning and testing should help avoid this type of accident. DB2/400 currently allows a maximum of 200 levels of nested triggers.

Application Performance Considerations

If you take the same edit from a number of application programs and put it instead in a trigger program, the performance impact should be minimal, since the same type of processing is done, only at a different level. Adding cascading or nested triggers on a database file where there was none before can translate into a noticeable downgrade in performance. The following example, from the DB2/400 Programmerís guide, illustrates the potential use for triggers:

Using Triggers in Conjunction with Referential Constraints

What are the basics of referential integrity? Referential integrity is a broad term encompassing all the mechanisms and techniques that ensure the validity of referenced data in a relational database. Referential constraints are a mechanism to enforce a level of validity desired in your database. Beginning with Version 3 Release 1 this capability became part of the OS/400 Operating System.

Database users want referential integrity implemented in their database management system for several reasons:

To ensure data values between files are kept in a state that meets the rules of their business. For example if a company has an order entry system, where each order has a header and a number of details; it makes no sense to add a detail if there is no header.

To be able to define the relationships between data values.

To have the system enforce the data relationships no matter what application makes changes.

To improve the performance of integrity checks done in a HLL or SQL level by moving the checking into the database.

When used in conjunction with referential integrity, triggers on a given file are processed first, along with all nested triggers. Once that action is complete, the referential integrity check occurs and verifies that the changes conform to the rules established. The program can thus resolve integrity violations prior to the referential constraint check. This is a powerful feature! Note that when using a trigger program in conjunction with referential integrity, you must journal the files affected. Note also that a trigger program can verify the data being written and send a signal based on what it found. It cannot however modify the data you are about to write to or update in a database file.

Commitment Control Considerations

A trigger program can perform a number of updates, as we have seen in the example shown earlier. It can also do more elaborate checks in conjunction with these updates. These checks can result in success or failure. For example: Assume you have three nested triggers on three different files; A, B and C. Your high level language application writes a record to file A. This triggers a (nested trigger) program to write to file B. This in turn triggers a (nested trigger) program that writes to file C and does a reference check to ensure that all three files are as expected. Now, let the reference check made by the trigger attached to file B fail and send back a negative result for the final check to OS/400. In a situation where files A, B and C would be journaled, all the trigger-written records would be automatically rolled back. If these files were not journaled, then the data would remain updated as is after the trigger was processed, good or bad.

This is a very basic example to illustrate the potential for combining triggers with commitment control. There are other ramifications beyond this simple example in such a situation and serious reading of reference manuals is recommended before starting on this path. Note that triggers can be used without journaling. A trigger program can be used, for example, even to send a message to a workstation. Basically, it will do anything you can now do in a high level language program.

In Conclusion

Triggers are still new to most of us. In this article, we only have skimmed the surface. The concept is simple enough: Attach the process to the database level, and forget having to put it at the application level. Great! But then there are so many other considerations. Commitment control can be a key component of a trigger-driven strategy for database integrity. It must however, be well understood and planned before starting out. Referential constraints is an other powerful new tool available and it seems like a natural to work hand-in-hand with triggers. These two examples are obvious ones, but truly, the potential for using trigger process in daily data processing situations can be much wider.

There is so much to say and we have not even touched the subject of writing an actual trigger program! This article is really only an introduction to DB2/400 Triggers; an invitation to further reading on the subject. Following this paragraph is a bibliography that you will likely find useful to dig into before starting to write your first trigger-driven applications.

Trigger Tips

How to find the program that initially fired the trigger
Where can I find a good example of a trigger program?

On how to find the program that initially fired the trigger, Rick wrote:

In my trigger program I need to know what program
caused the event that caused the trigger program to execute.

Answer:
Rick Santiago found the answer himself and provided the solution for this unusual problem. He wrote:

I found a way to find out what program called the trigger program. I found this article thru google (The same way I found your article) that detailed the use of a CLP program to retrieve the name of the program that called the trigger. http://faq.midrange.com/data/cache/95.html from this article I wrote the CLP program below. I modified the concept from the article so that I would only have to call the CLP program once and it will return the first non "Q" program it finds. I tested it yesterday by calling it from a test CLP program and it correctly identified the calling program.

PGM PARM(&CALLED &CALLER)

DCL VAR(&CALLER) TYPE(*CHAR) LEN(10)
DCL VAR(&CALLED) TYPE(*CHAR) LEN(10)
DCL VAR(&M1KEY) TYPE(*CHAR) LEN(4)
DCL VAR(&M1DTA) TYPE(*CHAR) LEN(80)

LOOP: SNDPGMMSG MSG('TEST') TOPGMQ(*PRV (&CALLED)) +
MSGTYPE(*RQS) KEYVAR(&M1KEY)
MONMSG MSGID(CPF0000) EXEC(DO)
CHGVAR VAR(&CALLER) VALUE(' ')
GOTO CMDLBL(END)
ENDDO

RCVMSG PGMQ(*PRV (&CALLED)) MSGKEY(&M1KEY) +
SENDER(&M1DTA)

CHGVAR VAR(&CALLER) VALUE(%SST(&M1DTA 56 10))

IF COND(%SST(&CALLER 1 1) *EQ Q) THEN(DO)
CHGVAR VAR(&CALLED) VALUE(&CALLER)
GOTO CMDLBL(LOOP)
ENDDO

END: ENDPGM

Go Back to the Top

On Where to find a good example of trigger programs on the Internet:


Answer:
A very clear and easy to follow example has been written by Alex Jayasundara, of Toronto. He graciously allowed Tylogix.com to post a copy on this site:
A good trigger program example written in ILE RPG by Alex Jayasundara

Note from the Author:

From V5R1 IBM doesnít guarantee that Dynamic Area of the trigger buffer is just after the Static Area of the trigger buffer. That is what the following link says. http://www-1.ibm.com/servers/eserver/iseries/db2/trigger.htm. In more detail what they are saying is even before and after Images are not guaranteed to be contiguous. This indirectly says that complete length of the trigger buffer cannot be predetermined and subject to change for each and every execution.

Now the real part comes: Since we have to use offset values only function that came to my mind was %ADDR function in RPG and it works fine. Sorry to say that I was unable to find an equivalent function in COBOL so far. So finally what I did was let RPG program to drive the trigger and obtain before and after images and simply call a COBOL program using before and after images as parameters. I have tested is and it works fine. I am attaching the complete source code with this. Currently I am planning to add a log file to the program so before and after images will get saved prior to transfer.

Go Back to the Top

Bibliography

DB2/400 Design Concepts:
Referential Integrity and Triggers,
Sharon L. Hoffman, Midrange Computing
ISBN 1-883884-29-2

DB2/400 The New AS/400 Database,
Skip Marchesani, Midrange Computing
ISBN 1-883884-12-8

DB2/400 Advanced Database Functions,
IBM Redbook: GG24-42-49-00

Stored Procedures
and Triggers
on DB2 Universal Database for iSeries

Back to Tylogix Home Page