Programming Triggers
Configuring triggers is a simple process using SQL CREATE/ALTER
TRIGGER statements programmatically or using Enterprise Manager.
The most involved step involves writing the actual BBj code that each
trigger will execute when it fires.
When coding triggers, BASIS recommends using the powerful BASIS IDE for editing the code. This gives the developer the added benefit of syntax highlighting and code completion.
Several BASIS Advantage articles contain additional examples of triggers and real-life use case scenarios. Enter “triggers” in the powerful search engine on the BASIS website www.basis.cloud for a list of the additional resources that discuss triggers.
BBjTriggerData
Most triggers need to have access to a variety of information about the file operation that was called, causing the trigger to fire. The BBjTriggerData object provides this access. The following code snippet shows how to acquire the BBjTriggerData object for the trigger:
declare BBjTriggerData td!
td!=BBjAPI().getFileSystem().getTriggerData()
There are numerous methods available on the BBjTriggerData object. For a complete description, see BBjTriggerData. Each method provides access to information such as the read buffer, write buffer, KEY= values, file name, etc. Look over the available methods to get familiar with the capabilities before beginning to write triggers. Read on for specific considerations of each type of trigger that will make the getting started process easier.
Error Trapping/Handling
Proper error handling in triggers is very important so that they operate seamlessly with the application. Handling errors is quite simple. The THROW call allows the developer to specify a completely custom error message as well as a meaningful error number based on the type of error. Below is an example of what should be done in all trigger source code files:
REM Put at top of the file
seterr handleError
REM All your trigger code here
…
REM Error handling section
handleError:
REM Optional: Log the error to the BBjServices.err
file
msg$ = "Error #" + str(err) + "
occured in " + pgm(-1) + " at line " + str(tcb(5))
REM Throw a customer error message with a particular
error number
myErrNum = 0
throw "My custom error message", myErrNum
Write Triggers
Write triggers are probably the most common type of trigger used. Write triggers fire when a write operation is called on the file system. They make it possible to validate or modify the data before it is written to disk, or to write data to another location such as a data warehouse or audit file, after the data is written to the file. Further, an instead of write trigger can even be used to write to another location entirely, never even touching the actual data file. The following examples show the basic information that might be useful in each of the types of write triggers.
Most of what is needed in ‘before/after/instead of’ write triggers is access to the write buffer. This example shows how to acquire the write buffer and also how to make changes to it to affect what will be written to disk (in a ‘before write’ trigger).
declare BBjTriggerData td!
td!=BBjAPI().getFileSystem().getTriggerData()
REM Get the write buffer for validation or modification
writeBuf$ = td!.getWriteBuffer()
REM Modify the write buffer and then change what will be written
REM to disk. This will only have affect in a before write
writeBuf$ = "New Value"
td!.setWriteBuffer(writeBuf$)
Read Triggers
When writing triggers, it is very important to take performance into account. Keep in mind that each time a file operation occurs, any triggers for that type of operation will fire. Sometimes this is not a huge issue for write or remove operations, but for read operations, this can make or break a project. Make sure that any read triggers are as streamlined and optimized as possible.
Read triggers typically make use of more BBjTriggerData methods than any other type of trigger type. The following example shows how to acquire various pieces of information about the read operation that fired the trigger (for a complete list of methods available, see BBjTriggerData:
declare BBjTriggerData td!
td!=BBjAPI().getFileSystem().getTriggerData()
REM Called in after read triggers to see that data read from disk
readBuf$ = td!.getReadBuffer()
REM Called in a after read trigger to modify the record returned
REM to the application.
td!.setReadBuffer(modifiedRec$)
REM Returns the KEY= value used on a READ RECORD call
key$ = td!.getKey()
REM Returns the current key number
key$ = td!.getKeyNumber()
Key Triggers
Key triggers fire when any of the following BBj functions are called: KEY, KEYP, KEYN, KEYF, and KEYL. Most key triggers will typically need access to two things: type of key call, and the value returned by the key call. In addition, the trigger can access things such as the key description, key number, key name, etc. Refer to see BBjTriggerData for complete details.
The following example shows some of the calls that a typical key trigger might use:
declare BBjTriggerData td!
td!=BBjAPI().getFileSystem().getTriggerData()
REM Get the key value read from disk in an after key trigger
REM NOTE: getKey() is NOT valid in a KEY trigger
keyValue$ = td!.getReadBuffer()
REM Get the type of key call that was made. Returns KEY, KEYF, KEYL,
REM KEYN, or KEYP
keyType$ = td!.getKeyCallType()
REM In a after key trigger, this will set the value returned
td!.setReadBuffer("Modified Key")
Remove Triggers
‘Remove’ triggers fire when a REMOVE call or SQL DELETE operation is made. The primary information of interest is the key value. The following example shows how to acquire this information:
declare BBjTriggerData td!
td!=BBjAPI().getFileSystem().getTriggerData()
REM Get the key value of the record to be removed.
keyValue$ = td!.getKey()
Open Triggers
Open triggers are called any time the file is opened. Open triggers are interested in the file name, and typically the MODE string:
declare BBjTriggerData td!
td!=BBjAPI().getFileSystem().getTriggerData()
REM Get the file name.
fileName$ = td!.getFilename()
REM Get a value from the MODE string used on the open
uid$ = td!.getModeValue("UID")
Erase/Close Triggers
The only piece of information that is really useful to these types of triggers is the name of the data file:
declare BBjTriggerData td!
td!=BBjAPI().getFileSystem().getTriggerData()
REM Get the name of the file
fileName$ = td!.getFilename()