What Return Codes Are Used in TRIG_RETC and How Can They Be Set?
Whenever a trigger function completes its completion status is subjected to 3 tests:
1. The return code TRIG_RETC is checked for "OK" (uppercase). If not "OK", then the trigger is deemed to have failed.
2. The function completion status is tested. If not okay, then the trigger is deemed to have failed. A function will give a "bad" completion status if it issues an ABORT command, or hits an ENDCHECK with no last display, or uses an invalid array or substring reference, etc, etc.
3. The IBM i completion status is tested. If not okay, then the trigger is deemed to have failed (e.g.: trigger function not found).
When a trigger function is deemed to have failed, a return code is then issued to the actual invoking function issuing the database operation (i.e. the function doing the SELECT or UPDATE or INSERT) according to the following table:
Operation In Progress | Return Code |
Before Open |
OK, ER |
After Open |
OK, ER |
Before Close |
OK, ER |
After Close |
OK, ER |
Before Read |
OK, ER |
After Read |
OK, ER |
Before Insert |
OK, VE |
After Insert |
OK, ER |
Before Update |
OK, VE |
After Update |
OK, ER |
Before Delete |
OK, VE |
After Delete |
OK, ER |
You should not return values in TRIG_RETC outside of those specified in this table.
Nor should the invoking RDML I/O command be set up to do any special "trapping" or "handling" when it knows that there is an underlying trigger.
Such an approach would create very complex designs and defeat the whole purpose for which triggers were introduced (i.e. being "invisible" to the upper layer of functionality).
RDML functions doing I/O operations are recommended to not use the IO_ERROR or VAL_ERROR parameters (like any other normal RDML functions).
Leave the default values and let the standard error handling solve the problem. Use a "binary" approach to doing I/O operations - it either worked or it didn't work - and if it didn't work let the standard error handling solve the problem.
Coding your own I/O error traps in RDML functions is not recommended unless they are of a very specialized nature (e.g.: setting up work files). Failing to observe this recommendation will lead to overly complex implementations that exhibit no real business benefit and cost significantly more to develop and maintain.
An "OK" response indicates that the operation completed normally.
An "ER" response sets the IO_ERROR parameter in the RDML command that issued the I/O request.
A "VE" response sets the VAL_ERROR parameter in the RDML command that issued the I/O request.
Note that the "VE" response is only possible for before insert, before update and before delete.
This allows triggers in these positions to act like "extended validation checkers".
However, a trigger set up as an "extended validation checker" cannot actually "flag" a specific field as being in error.
It can indicate an error has occurred, and it can issue error message details, but it cannot flag the specific field in error in the same way that a normal validation rule can, or in the same way that a normal validation checking function can (see function option *xxx_FIELD_VALIDATE).
However, an "extended validation checker" defined as a trigger has one advantage over a normal validation checking function: it has access to all the values in the record of a file that is being inserted, deleted or updated - whereas a normal validation function only has access to the individual field value with which it is associated.
Using a trigger as an "extended validation checker" is a very powerful facility, especially when the "before and after images" available to the before update check are considered, and as such it can be very useful at times.
However:
- Reserve the use of "extended validation triggers" for truly complex situations. Do not use this facility without even considering the normal dictionary facilities.
- Where "extended validation check" type triggers are to be used, have just one per file and encapsulate all the rules inside it. You then have just one trigger that supports the action "Validate".
- Make trigger functions exhibit "insulated modularity". Like action bar functions they should exhibit these "OO" like characteristics:
- They should perform one and only one "action".
- They should not expect other triggers or virtual code logic to precede, or to follow them.
- They should operate "standalone".
- They should be small and robust. When a trigger is invoked to perform an action it should just do that single action or issue an error message indicating why it cannot.