User Exit 4 (User-Generated Log Data)

#### Search Results

Search

# User Exit 4 (User-Generated Log Data)

User exit 4 is called immediately before an Adabas command log record is to be written. It may be used to generate any required user log data (SMF records) special statistics, or to suppress writing a log record.

For more information regarding Standard MVS Calling Conventions and Return from User Exits please refer the respective sections in the Overview.

Note
User exit 4 is still called even if ADARUN LOGGING=NO and REVIEW is specified. User exit 4 will not be invoked if LOGGING=NO and REVIEW is not active. If REVIEW is specified, the only way to disable user exit 4 is to remove the ADARUN UEX4 parameter from the Adabas run.

This document covers the following topics:

- Command Log Format

- Invoking User Exit 4

- Accessing Adabas Buffers via CQX

- Accessing Adabas Buffers via LORECX

## Command Log Format

Adabas supports two different command log formats. The ADARUN CLOGLAYOUT parameter determines which format is used:

- CLOGLAYOUT=5 (the default) is supported only in Adabas versions 5.2 and above.

- CLOGLAYOUT=8 specifies the new format, which is supported only in Adabas versions 8 and above.

Both formats are described in Command Log Formats.

Ensure that your user exit and command log evaluation programs recognize the format in use before switching to it.

##### User-Generated Log Data User Exit (4) Parameters

1Address of ACB Copy: This address should be set to zero if the command is using an ACBX interface direct call.

2Address of the first ABD: The Adabas buffer descriptions (ABDs) are in a contiguous array. For complete information about locating ABDs in this array, read Locating the Correct ABD, elsewhere in this section.

Parameter | Address of . . .
--- | ---
0(R1) | a byte containing a logging action code. This byte contains: +00 -- action code to log the record upon each call. If changed to a nonzero value, this record will not be written to DDLOG. +01 -- reserved for future use +02 -- two-byte database ID.
4(R1) | the record to be logged. This address is zero if the exit is called at the end of the nucleus session.
8(R1) | the end of the Adabas I/O area. This address is zero if the exit is called at the end of the nucleus session.
12(R1) | the command queue element (CQX). This address is zero if the exit is called at the end of the nucleus session.

The record to be logged may be modified by the user exit. The record's address in 4(R1) may also be modified. The logging action code must always be specified before returning to the Adabas nucleus.

| Warning: When modifying the record, do not exceed the end address of the ADALOG I/O area contained in 8(R1).

#### Locating the Correct ABD

Internally, Adabas 8 only uses extended Adabas control blocks (ACBX) and Adabas buffer descriptions (ABDs). Direct calls made using the classic Adabas control block (ACB) and buffer definitions have their data structures converted to ACBX calls and ABDs by ADASVC before the nucleus sees the call. Thus, the protocol for locating and accessing buffers in user exits, such as this one, has changed as of Adabas 8.

The Adabas buffer descriptions (ABDs) are now in a contiguous array. However, the internal representation of the ABD may not have the same length as the base ABD, as defined by the value of the ABDXQLL symbol in the ADABDX DSECT, although the first ABDXQLL bytes continue to be mapped by ADABDX. This means that you should not use the ABDXQLL value in the ADABDX DSECT to locate the next ABD in the ABD array. Instead, you should use the value of the two-byte ABDXLEN field at offset `+x'00'` of the ABD to determine the end of that ABD and the start of the next ABD in the array. Do not assume that all internal ABD representations have the same length: each must be located in turn by applying its predecessor's ABDXLEN value.

In addition, the order of the ABDs is not defined and my change over time or from command to command, although within the array all ABDs of a given type (format buffer, record buffer, etc.) are contiguous. There will be an ABD for every buffer provided by the user that is documented as an input or output buffer for the specific command. There may also be additional buffers created by other components. When there are multiple instances of format, record and (optional) multifetch buffers, they are related based on their position: the first format buffer is associated with the first record (and optional multifetch) buffer, the second with the second, and so forth. If the caller provides an unequal number of format, record and (optional) multifetch buffers, dummy descriptors with a zero buffer length are created to bring about equal quantities. When multifetch is used with a classic ACB call, certain commands (L1/2/3/4/9) will have their ISN buffer converted into a multifetch buffer. Here are some examples:

- If a caller (using either an ACB or ACBX call) issues an OP command and provides a record buffer and search buffer, the array of ABDs will have one record buffer ABD and one dummy format buffer ABD (to satisfy the internal requirement that there be equal numbers of format and record buffers). There is no ABD for the search buffer because that is not a documented input or output buffer for the OP command.

- If a caller uses an ACBX call to issue an L1 command and provides two format buffers and three record buffers, the array of ABDs will have three record ABDs and three format ABDs, the last one of which is a dummy format ABD. The first record buffer is associated with the first format buffer; the second record buffer is associated with the second format buffer; and the third record buffer is associated with the third (dummy) format buffer.

- Suppose a caller uses an ACB call to issue an L3 command with Command Option 1 set to "M" (multifetch) and Command Option 2 set to "A" (ascending retrieval from a specified value). In addition, the caller provides a format buffer, a record buffer, an ISN buffer, a search buffer and a value buffer. In this case, the array of ABDs will have one format buffer ABD, one record buffer ABD, one multifetch buffer ABD, one search buffer ABD, and one value buffer ABD. The caller's ISN buffer will have been converted to a multifetch buffer.

## Invoking User Exit 4

User exit 4 is invoked for every record which is written to the CLOG. The kind of record can be determined by field LOXTYPE of structure LORECX (`<R1> + 4` => LORECX).

The set of records written to CLOG depends on the Adabas command (valid buffer types) and the corresponding ADARUN parameters (LOGGING, LOGABDX, LOGCB, LOGFB, LOGIB, etc. referred to as LOGxxx later).

#### Sample

    ADARUN LOGGING=YES,LOGCB=YES,LOGRB=YES,LOGSB=YES
    OP command with RB="ACC=10."

Will result in invocations of UEX4 with:

1. Basic record including control block (`LOXTYPE= x’0001’`)

2. ABDX + record buffer (`LOXTYPE = x’0008’`)

## Accessing Adabas Buffers via CQX

<R1> + x’0C’ | CQX structure (Command Queue Element info for Adabas user exits)
CQX + x’48’ | ACBX structure
CQX + x’50’ | number of ABDs
CQX + x’54’ | array of ABDs, length of array element is ABDXLEN (i.e. step forward to next array element by adding its length ABDXLEN)

Depending on the value of ADBXLOC, you get to the buffer itself. In this scenario the value of ABDXLOC is ‘I’ and ABDXADR contains the address of the buffer. It points directly to the value; there is no preceding length field.

The length of the buffer can be obtained from

- ABDXSIZE the allocated length of the buffer

- ABDXSEND the length of data send to Adabas

- ABDXRECV the length of data received from Adabas

The simplest way is to use `“LENGTH = max(ABDXSEND,ABDXRECV)”` but make sure this does not exceed ABDXSIZE.

#### Sample accessing Adabas buffers via CQX

Assuming the LOGxxx ADARUN parameters are set accordingly.

    If LORECX.LOXTYPE eq LOXTBAS then                    /*? Adabas basic record
      "process ACBX pointed by CQX.CQXACBX"
      #n := pointed by CQX.CQXPNBD                       /* number ABDX
      If #n gt 0 then                                    /*? Any  ABDX present
        #s := pointed by CQX.CQXPABD                     /* address 1st ABDX
        For #i := 1 to #n                                /* iterate for all ABDX
          #l := max (#s.ABDXSEND, #s.ABDXRECV)           /* l’data
          If #l > 0
            Then "process  ABDX pointed by CQX.CQXPABD"
          End-if
          #s := #s + #s.ABDXLEN                          /* step to next ABDX
        End-for
      End-if
    End-if

## Accessing Adabas Buffers via LORECX

When accessing the Adabas buffers via LORECX structure one has to “listen” for records with LOXTYPE:

- x'0001'
  the basic record containing the ACBX (optional) and the fields LOX1TYP1 and LOX1TYP2 which define and illustrate which "data records" (LOXTYPE= x'0008' and x'0009') will follow.

- x'0008'
  ABDX and buffer

- x'0009'
  buffer continued (in case the data overflows the record length)

### On this page

- Command Log Format
- Invoking User Exit 4
- Accessing Adabas Buffers via CQX
- Accessing Adabas Buffers via LORECX