Writing expression user exit programs

User exit programs must be IBM® Language Environment® compliant, and use reentrant coding techniques and standard OS linkage. The expression user exits must be compiled and link-edited to use AMODE 31 (31-bit addressing).

Before active replication begins during the subscription's initialization, each expression user exit program is called with the CALLTYPE field of the USRDATA predefined structure set to “Initialize” (value 2). This allows each entry point to provide code to obtain resources it will require, before any replication activities have started. Such initialization processing could include obtaining virtual storage resources, opening a file, obtaining onetime information from Db2® tables, and so on.

After active replication is complete during the subscription's termination, each expression user exit program is called with the CALLTYPE field of the USRDATA predefined structure set to “Terminate” (value 3). This allows each entry point to provide code to release resources it required, after all replication activities have ceased. Such termination processing could release obtained virtual storage, close an opened file, etcetera.

For CALLTYPE values of “Initialize” and “Terminate” (values 2 and 3), no user parameters (if applicable) are passed to the user exit program in the XVAR predefined data structures.

While active replication is ongoing, each entry point that you define in an expression user exit program is called with the CALLTYPE field of the USRDATA predefined structure set to “Process” (value 1). This indicates that the expression user exit program is being called for its processing purpose, and that user parameters (if applicable) are being passed to the user exit program in the XVAR predefined data structures.

It can be seen from the paragraphs above that each entry point is called at least twice. For instance, if an expression user exit is specified in a %USER function of an expression, it is called twice even if there were no changes replicated between the times that the subscription was started and stopped. You must provide code in an expression user exit for detecting and processing the “Initialize” and “Terminate” values of the CALLTYPE field of the USRDATA predefined structure, otherwise the result will be unpredictable, and the expression user exit program could abnormally terminate.

When an expression user exit completes its processing, in addition to the return value that is returned through the first pointer, the user exit program that you write must pass back a return code to InfoSphere® CDC. This return code is the value returned by a program/function call. In the COBOL language, the return code is stored in the RETURN-CODE special register before the GOBACK statement for the program is executed. In C language, the return code is provided as the value of a return statement. In Assembly Language, the return code is provided as the value of the RC keyword in the RETURN macro instruction. InfoSphere CDC recognizes the following return codes and responds as indicated in the following table:

User Exit Program Call Type (CALLTYPE Value) Return Code Definition/Response
Process (1) 0 The user exit program processing call was successful. InfoSphere CDC continues normal processing.
  8 InfoSphere CDC reports a minor error.

If the expression containing the %USER function is processed in the target environment, replication activities are stopped if the ENDONERROR parameter has been set to “YES” for the specific replication activity (Refresh, Mirror, Audit).

If the expression containing the %USER function is processed in the source environment, replication activities are stopped unconditionally.

  12 InfoSphere CDC reports a severe error, and replication activities are stopped.
Initialize (2) 0 The user exit program initialization call was successful. InfoSphere CDC continues normal processing.
  Nonzero value An error was encountered during the user exit initialization call. InfoSphere CDC reports the error, and replication activities are not started.
Terminate (3) 0 The user exit program termination call was successful. InfoSphere CDC continues normal processing.
  Nonzero value An error was encountered during the user exit termination call. InfoSphere CDC reports the error, but due to the type of call, normal processing continues.

User exit programs can also issue Db2 SQL statements. Such SQL statements must be issued through the standard Db2 High-level Language Interface. Programs that contain Db2 SQL statements must be prepared using the Db2 precompiler or the corresponding language's SQL coprocessor (if available).

User exit programs cannot issue COMMIT or ROLLBACK SQL statements unless they are called with the CALLTYPE field of the USRDATA predefined structure set to “Terminate” (value 3). For any other value of CALLTYPE, an SQL COMMIT or ROLLBACK statement issued from a expression user exit will be intercepted by InfoSphere CDC and suppressed, and the SQLCODE value received from the SQL COMMIT or ROLLBACK statement will be 0.

Expression user exits that are coded within row filtering expressions or within source expressions are called from the z/OS® task that implements the InfoSphere CDC Logical Scrape process. Since no changes are made to application tables at the source side, there can be no expectation of a COMMIT or ROLLBACK being issued by InfoSphere CDC at the source side, and any SQL statements issued from within expression user exits called on the source side may never be committed. It is improper to code any SQL statements that actually change application data tables in expression user exits called on the source side of a subscription. SQL statements that query application data can be coded.

Expression user exits that are coded within an expression on the target side are called from the z/OS task that implements the InfoSphere CDC Apply process. For this reason, any changes made to application data tables using SQL statements issued from within expression user exits will be committed or rolled back when InfoSphere CDC issues its SQL COMMIT or ROLLBACK statement for the commit group it was applying when it called the table-level user exits and row-level user exits. Any changes arising from SQL statements issued from within table-level user exits and row-level user exits will be in the same logical unit of work (LUoW) at the target side as the changes that were passed to the user exits when they issued the SQL statements.

Under certain detected deadlock or timeout conditions, Db2 will internally ROLLBACK a unit of work and indicate this to the issuer of the last SQL statement for the unit of work by setting the SQLCODE to -911 or -913. When SQL statements are issued from expression user exits, such an SQLCODE is intercepted by InfoSphere CDC and not presented to the expression user exits. Instead, an SQLCODE of 0 is presented. InfoSphere CDC will then recover from the ROLLBACK condition by reissuing all the SQL in the current unit of work. In doing so, InfoSphere CDC will also recall any expression user exits for the changes being (re)applied. For this reason, it is not necessary to code logic in the user exit programs to check for SQLCODE values of -911 or -913 being returned from any SQL statements, nor to provide the attendant logic to handle such SQLCODE values.

The USERDATA field in the USRDATA predefined structure is meant to be used by the user exits as a common resource field. It is defined in COBOL as a POINTER, in C as a void *, and in Assembly Language as an A-con. Initially, when the subscription starts, this field has all bits reset, which is equivalent to the POINTER value NULL/NULLS in COBOL or the pointer value NULL in C. The content of this field is never accessed or altered by InfoSphere CDC after the subscription has started. The content of this field is passed to all the user exits for all tables within a subscription. Each user exit receives the contents of this field as they were when the previously called user exit returned control to InfoSphere CDC. The first user exit to receive control for any table within the subscription can initialize the USERDATA field. For example, the first user exit to receive control can store a pointer to acquired storage in this field, and the acquired storage can be used to convey data and communicate status to subsequent calls of any of the provided expression user exits for all tables in the subscription. It is the responsibility of the user exits to release any resources they acquire before a subscription ends.

Because all expression user exits are driven by the single task that implements the Scrape or Apply process for a subscription within InfoSphere CDC, the expression user exits will be driven consecutively, and no two expression user exits will ever receive control concurrently within the same subscription. This effectively enforces a serialization on the content of the USERDATA field, and any user exit can examine and modify the content of the USERDATA field (or whatever data structure to which it points) without concern for serializing the accesses.

Any activity within an expression user exit that involves “blocking” services (for example, issuing a Db2 SQL statement), or suspending execution (for example, issuing an Assembly Language WAIT macro instruction), will suspend the entire Scrape or Apply process, and delay the subscription. Try to design the expression user exits to minimize or eliminate the use of such services.

Frequently, it may be desirable for a table-level user exit and row-level user exit to generate a message describing a detected condition before it concludes. For example, a set of before insert, before update and before delete row-level user exits that implement prechecking for and mitigation of operational errors (“row not found” and “duplicate key”) may want to issue a message describing the steps they took to eliminate an operational error. Such a message would be something like:

Operational Error avoided, UPDATE for key “1234” of CUSTOMER_ACCOUNT table was changed to an INSERT

A message of this nature should be associated with other messages from the subscription in the event log. To achieve this, the USRMSG field of the USRDATA predefined structure can be used. Text for the message should be stored in the USRMSG field. This text must not exceed 512 characters, and the first character must not be a blank character. Only valid graphic display characters that can be entered on a keyboard should be used and the USRMSG field should be blank-padded to the full 512 characters. This text will be used to issue a CHC0335I message. This message will appear in the Event Log for the subscription, and in the CHCPRINT spooled data set. The subscription will continue according to the specification of the return code, as described above.

Expression user exits must be coded, compiled and link-edited as reentrant programs. This is generally as simple as specifying the RENT option for the compiler and the linkage editor. If an exit is written in Assembly Language, specific design and coding accommodations are required to produce reentrant code. If InfoSphere CDC loads a expression user exit and detects that it is not marked as reentrant by the linkage editor, then initialization of the associated subscription will fail and the subscription will terminate. If a expression user exit is marked reentrant by the linkage editor but is actually not executing according to the requirements of reentrancy, then unexpected errors can result, including the failure of the expression user exit, or corruption of the data being passed to the expression user exit.

During development and testing, and sometimes during production execution, user-written expression user exits may experience error conditions that result in an abnormal termination. For example, an expression user exit may attempt to store data into a virtual storage area using a storage reference pointer, but inadvertently, the storage reference pointer contains the NULL pointer value. This will result in an ABEND S0C4 (General Protection Fault). Normally, InfoSphere CDC intercepts all abnormal terminations that arise from within expression user exits. InfoSphere CDC then issues an explanatory message to the Event Log and CHCPRINT spooled output data set, and terminates the subscription that called the failing expression user exit. Based on the Language Environment options provided to the InfoSphere CDC address space, LE may produce a diagnostic printout of the intercepted error, or permit a dump of the address space at the time of the error to occur. It is also possible to specify Language Environment options that inhibit InfoSphere CDC from intercepting such catastrophic errors. In this case, the catastrophic error is elevated to InfoSphere CDC itself, and the entire InfoSphere CDC address space may fail. It is the your responsibility to locate and fix any errors in their expression user exits. Judiciously specified Language Environment options, coupled with diagnostic tests and messages issued from within the expression user exit can be helpful in achieving this goal. The Language Environment options that disable the interception of abnormal terminations within the Language Environment enclave should not be used unless for a specific issue and in a controlled environment.