User Exits And Hyperexits

#### Search Results

Search

# User Exits And Hyperexits

This document contains an explanation of the user exits and hyperexits that are supported by Adabas.

This document covers the following topics:

- User Exits Overview

- User Exit Descriptions

- Hyperexits Overview

- Hyperexit Control Block and Buffers

- Hyperexit Interfaces

- Creating and Defining User Exits and Hyperexits

## User Exits Overview

A user exit is a user-written routine that enables the user to participate in the processing performed by the Adabas nucleus or Adabas utilities. It is enabled by nucleus or utility input parameters. The user-written routine is dynamically loaded at the startup of the nucleus or utility, and is called at predefined stages in the processing of the nucleus or utilities.

The routines should be written in the C programming language.

The user exit must be present as a dynamic shared library (Linux) or as a dynamic link library (Windows). This means that a user exit or hyperexit has to be compiled and linked with the corresponding options. A shared library requires position-independent code, therefore the compiler must be called with the PIC option. A dynamic link library (DLL) must be compiled for multi-threading.

Adabas uses environment variables to locate user exits. See the section Creating and Defining User Exits and Hyperexits for details.

The following user exits are available for Adabas:

User Exit | Use
--- | ---
Nucleus user exit 1 | user processing on a direct Adabas call before it is processed by the nucleus (located using the environment variable ADAUEX_1)
Nucleus user exit 2 | user processing at the close of a protection log file or command log file (located using the environment variable ADAUEX_2)
Nucleus user exit 4 | user processing on a CLOG output record before it is written to the CLOG file (located using the environment variable ADAUEX_4)
ADACMP user exit 6 | user processing on an ADACMP input record before it is compressed by ADACMP (located using the environment variable ADAUEX_6)
ADAULD user exit 7 | user processing on a compressed ADABAS record before it is processed by ADAULD (located using the environment variable ADAUEX_7)
Nucleus user exit 11 | user processing on a direct Adabas call before it is processed by the nucleus (located using the environment variable ADAUEX_11)
Nucleus user exit 14 | user processing on a CLOG V6 output record before it is written to the CLOG file (located using the environment variable ADAUEX_14)
Nucleus user exit 21 | set authentication credentials via the Adabas Server API Functions
ADALNK user exit 0 | user processing before Adabas call execution (located using the environment variable LNKUEX_0)
ADALNK user exit 1 | user processing after Adabas call execution (located using the environment variable LNKUEX_1)
ADALNKX user exit 0 | user processing before Adabas call execution (located using the environment variable LNKUEX_ACBX_0)
ADALNKX user exit 1 | user processing after Adabas call execution (located using the environment variable LNKUEX_ACBX_1)

At the startup of the nucleus, the user exit will be called first with an initialization call of the following form:

    uex_X (0, UEX_INIT*)

where X is the number of the user exit and can have the value 1, 2 or 4.

The structure UEX_INIT (defined in adauex.h) is used for input/output values between ADABAS and the user exit. The input parameters are the database ID and the current version. The user exit must inform ADABAS if the code is re-entrant or non re-entrant by setting uex_type to either UEX_REENTRANT or UEX_N_REENTRANT. The code may be declared re-entrant if it uses only variables of storage class automatic. If the code is non re-entrant, the calls to the user exits are serialized by ADABAS, whereas if the code is re-entrant, the calls can be done in parallel.

## User Exit Descriptions

- Nucleus User Exit 1

- Nucleus User Exit 2

- Nucleus User Exit 4

- ADACMP Utility User Exit 6

- ADAULD Utility User Exit 7

- Nucleus User Exit 11

- Nucleus User Exit 14

- Nucleus User Exit 21

- ADALNK-Specific User Exits

### Nucleus User Exit 1

#### Description

The ADABAS nucleus user exit 1 is a user exit that performs user processing on a direct ADABAS call. The routine is called when the processing of a command begins. The input parameters that are specified enable the user exit to change the parameters of the ADABAS call, or to reject the call so that the user who issued the call receives an ADABAS response 22 (invalid command).

The user exit is not allowed to change the command code or to change any of the buffer lengths that are specified in the ADABAS control block. Changing any of these values causes an ADABAS response 22 (invalid command) to be returned to the user who issued the command.

The nucleus user exit 1 is activated by setting USEREXITS=1 in ADANUC.

#### Input Parameters

    Format: uex_1 ( pcb, pfb, prb, psb, pvb, pib, pcq )

pcb: | Usage: | Adabas control buffer
| Type: | struct cb_par *
| Access: | read/write
| Mechanism: | by reference

For the structure of an ADABAS control block, see the Command Reference Manual.

pfb: | Usage: | Adabas format buffer
| Type: | unsigned char *
| Access: | read/write
| Mechanism: | by reference

If pcb is the 0-pointer, then pfb points to the UEX_INIT structure (at init call)

prb: | Usage: | Adabas record buffer
| Type: | unsigned char *
| Access: | read/write
| Mechanism: | by reference

psb: | Usage: | Adabas search buffer
| Type: | unsigned char *
| Access: | read/write
| Mechanism: | by reference

pvb: | Usage: | Adabas value buffer
| Type: | unsigned char *
| Access: | read/write
| Mechanism: | by reference

pib: | Usage: | Adabas ISN buffer
| Type: | unsigned char *
| Access: | read/write
| Mechanism: | by reference

pcq: | Usage: | Adabas command queue element
| Type: | struct cq_entry *
| Access: | read
| Mechanism: | by reference

For the structure of an Adabas command queue element, see the header file adauex.h.

#### Return Values

The user-exit return value is essentially an Adabas response code.

ADA_NORMAL: | Success. The nucleus checks whether illegal changes have been made in the control block. If no illegal changes are detected, the call is processed.
Else: | Failure. The Adabas call is rejected with a response 22 (invalid command).

### Nucleus User Exit 2

#### Description

The ADABAS nucleus user exit 2 is a user exit that performs user processing on a close of the command log file (CLOG) or protection log file (PLOG). The user exit is called after the file is closed in the following situations:

- Nucleus shutdown (ADAOPR SHUTDOWN or CANCEL function)

- Forced PLOG/CLOG change (ADAOPR FEOF function)

- Automatic PLOG/CLOG change (new extent).

- New PLOG after online dump (ADABCK NEW_PLOG function)

- During an Autorestart

This user exit can also be used to archive PLOGs.

The nucleus user exit 2 is activated by setting USEREXITS=2 in ADANUC.

#### Input Parameters

                Format: uex_2 ( sess_num, dbid, env_var_cnt, logname, status )

sess_num: | Usage: | PLOG session number
| Type: | int *
| Access: | read
| Mechanism: | by reference

sess_num is the number of the nucleus session. A value of zero indicates that the current PLOG is closed. If the pointer is 0, then it is the INIT-call. In this case, the next parameter points to the UEX_INIT structure.

dbid: | Usage: | database identifier
| Type: | int *
| Access: | read
| Mechanism: | by reference

dbid is a pointer to the database identifier. If sess_num is the 0-pointer, then it points to the UEX_IMT structure (at init call).

env_var_cnt: | Usage: | environment variable counter
| Type: | int
| Access: | read
| Mechanism: | by value

env_var_cnt is the current environment variable counter that is used when using multiple environment variables. For the PLOG it will be 1 for NUCPLG, 2 for NUCPLG2, 3 for NUCPLG3 etc. The user exit is able to translate the environment variable in order to obtain the PLOG's path name.

logname: | Usage: | file name
| Type: | char *
| Access: | read
| Mechanism: | by reference

logname is the name of the PLOG/CLOG.

status: | Usage: | calling status
| Type: | int
| Access: | read
| Mechanism: | by value

status indicates the time at which the user exit was called. The possible values are UEX2_SWITCH for a PLOG/CLOG change, UEX2_SHUTDOWN at the end of the nucleus session, and UEX2_AUTORESTART when the nucleus comes up following a crash during an Autorestart.

#### Return Values

The user-exit return value is essentially an ADABAS response code.

ADA_NORMAL: | Success.
Else: | Failure. The Adabas nucleus prints a message that contains the user-exit return code. The user exit is disabled and will not be called again.

### Nucleus User Exit 4

#### Description

The Adabas nucleus user exit 4 is a user exit that performs user processing on a CLOG output record before it is written to the CLOG file. The user exit can shorten, extend or completely change the record. If the length or structure of the record is changed, the utility ADACLP, which is used to print CLOGs, may not be able to output the records that are created. A warning message is issued if a user exit was active when the CLOG records were written.

The nucleus user exit 4 is activated by setting USEREXITS=4 in ADANUC.

#### Input Parameters

    Format: uex_4 ( pcl, pcq, pdsc)

pcl: | Usage: | CLOG output record
| Type: | struct cl_entry *
| Access: | read/write
| Mechanism: | by reference

For the structure of a CLOG record, see the CL_ENTRY structure definition contained in adauex.h.

The length of the record is contained in the first two bytes of the CLOG record. Bytes 3 and 4, which contain information for ADACLP, must not be changed. The nucleus restores these bytes after the call to the user-exit routine.

The original length of the user-exit input record must not be increased. Additional data may only be returned by the user exit using the additional descriptor. The length of the CLOG record returned plus the length of the additional buffer must not exceed 32763 bytes, which is the maximum record length that can be written to the CLOG. The Adabas nucleus then prints a message that contains the user-exit return code 0. The user exit is disabled and will not be called again.

If a CLOG record is to be suppressed, the user exit must set the first two bytes of the record, which contain the length, to zero.

pcq: | Usage: | Adabas command queue element
| Type: | struct cq_entry *
| Access: | read
| Mechanism: | by reference

If pcl is the 0-pointer, then it points to the UEX_INIT structure (at init call).

For the structure of an Adabas command queue element, see the description of user exit 1.

pdsc: | Usage: | buffer descriptor
| Type: | struct cl_dcs *
| Access: | write
| Mechanism: | by reference

pdsc is the address of a structure that describes a buffer which contains additional data for the CLOG record. The buffer is specified by length and a pointer. The information contained in the buffer is appended to the CLOG output record specified by the parameter pcl.

#### Return Values

The user-exit return value is essentially an ADABAS response code.

ADA_NORMAL: | Success.
Else: | Failure. The Adabas nucleus prints a message that contains the user-exit return code. The user exit is disabled and will not be called again.

### ADACMP Utility User Exit 6

#### Description

The ADACMP utility user exit 6 is a user exit that performs user processing on an ADACMP input record before it is compressed. The user exit may change or skip records, insert additional records or terminate the compression. The action to be taken is indicated by user-exit return values that are interpreted by the ADACMP utility.

The utility user exit 6 is activated by setting the USEREXIT option in ADACMP.

#### Input Parameters

    Format: uex_6 ( in_st , out_st )

in_st: | Usage: | user exit 6 input structure
| Type: | struct ue6_in *
| Access: | read
| Mechanism: | by reference

out_sc: | Usage: | user exit 6 output structure
| Type: | struct ue6_out *
| Access: | write
| Mechanism: | by reference

#### Return Values

The user-exit return value is returned in the output structure.

UE6_O_PROCESS: | Compress this record.
UE6_O_SKIP: | Skip this record without compressing it.
UE6_O_TERM: | Terminate compression of records immediately.
UE6_O_REPEAT: | Call user exit again with the same input record.

For the definition of these constants, the structure ue6_in and the structure ue6_out, see the include file adauex.h.

#### Other Information

The user exit routine must be written in C. The routine will be dynamically loaded.

ADACMP passes control to the user exit routine immediately after reading each input record. The user routine may modify, extend or shorten the record or may indicate to ADACMP that the record is not to be processed. One or more additional records created within the user exit may also be passed to ADACMP.

A pointer to an input parameter block and a pointer to an output parameter block are passed with each call (please see the header file adauex.h for more information). ADACMP provides the length and address of the input record area on each call. If an end-of-file condition is detected in the input file, ADACMP sets the input status to UE6_I_EOF and the input record length to 0. The user exit must place the address of the output area and the output record length into the output parameter block before returning to ADACMP. By default, ADACMP sets the input length and area and the output length and area to the same value. In order to leave a record unchanged, the user routine only has to execute a return instruction. If a record is not to be processed by ADACMP, the output status should be set to UE6_O_SKIP.

The user exit may indicate to ADACMP that control is to be returned to the user exit immediately upon ADACMP's processing of the current record (without reading the next record). This is done by setting the output status to UE6_O_REPEAT before returning to ADACMP. This technique may be used to pass a record created within the user exit to ADACMP.

If the user exit returns UE6_O_TERM in the output status, no further records will be processed.

    typedef struct ue6_in
    {

      unsigned long             ue6_i_status;
    #define UE6_I_NORMAL        1                /* standard call               */
    #define UE6_I_EOF           2                /* call after EOF on input     */
    #define UE6_I_REPEAT        3                /* repeat call on same record  */
                                                 /* because of previous output  */
                                                 /* status UE6_O_REPEAT

      unsigned long             ue6_i_len;       /* length of input record      */
      unsigned char*            ue6_I_ptr;       /* pointer to input record     */
    } UE6_IN;

    typedef struct ue6_out
    {
      unsigned long             ue6_o_status;
    #define UE6_O_PROCESS       1                /* process (compress) record   */
    #define UE6_O_SKIP          2                /* skip this record            */
    #define UE6_O_TERM          3                /* terminate compression       */
    #define UE6_O_REPEAT        4                /* call again before reading   */
                                                 /* next record from input file */

      unsigned long             ue6_o_len;       /* length of output record     */
      unsigned char*            ue6_o_rec;       /* pointer to output record    */
    } UE6_OUT;

#### Example

    #include <adabas.h>
    #include <adauex.h>

    #define  PERS_ID_OFFSET              0
    #define  SEX_OFFSET                 69
    #define  FULL_ADDRESS_OFFSET        76
    #define  ADDRESS_LENGTH             20
    #define  CITY_COUNTRY_DISPLACEMENT  30

    /*+
    **      NAME:
    **              uex_6 - adabas user exit 6 example
    **
    **      SYNOPSIS:
    **              int     uex_6 ()
    **
    **      DESCRIPTION:
    **              This USEREXIT requires uncompressed records
    **              of the example file EMPLOYEES as input.
    **
    **              It changes the personnel-id for all employees
    **              coming from Denmark (DK) and United States (USA).
    **              The personnel-id is changed in the way that for
    **              all female employees from Denmark the personnel-id
    **              starts with "40", for all male employees with "41".
    **              For all female employees in the United States the
    **              personnel-id starts with "20", for all male
    **              employees with "21".
    **              Additionally all employees from Spain are rejected
    **              and therefore those records are not compressed.
    **
    **      RETURN VALUES:
    **              always 0
    **
    **      FUNCTIONS USED:
    **              none.
    **
    -*/

    #ifdef __STDC__

    int uex_6 (struct ue6_in* ue6_in_ptr, struct ue6_out* ue6_out_ptr)

    #else

    int uex_6 (ue6_in_ptr, ue6_out_ptr)

    UE6_IN  *ue6_in_ptr;
    UE6_OUT *ue6_out_ptr;

    #endif
    {

      register unsigned char *country_ptr;
      register unsigned char *field_ptr;
      register unsigned char  mu_field_count;

      if (ue6_in_ptr->ue6_i_status == UE6_I_NORMAL)
      {

        /*
        ** calculate address of country in input record
        */

        field_ptr      =  ue6_in_ptr->ue6_i_ptr + FULL_ADDRESS_OFFSET;
        mu_field_count = *field_ptr;
        country_ptr    =  field_ptr + 1 + mu_field_count * ADDRESS_LENGTH +
                          CITY_COUNTRY_DISPLACEMENT;

        if (memcmp(country_ptr, "E  ", 3) == 0)
        {
          /*
          ** mark records of spanish employees to be skipped
          */

          ue6_out_ptr->ue6_o_status = UE6_O_SKIP;
        }
        else if ((memcmp(country_ptr, "USA", 3) == 0) ||
                 (memcmp(country_ptr, "DK ", 3) == 0))
        {
          /*
          ** modify personnel id for employees from denmark and USA
          */

          field_ptr  = ue6_out_ptr->ue6_o_ptr + PERS_ID_OFFSET;

          if (memcmp(country_ptr, "USA", 3) == 0)
          {
            *field_ptr = '2';
          }
          else
          {
            *field_ptr = '4';
          }

          if (*(ue6_out_ptr->ue6_o_ptr + SEX_OFFSET) == 'F')
          {
            *(field_ptr + 1) = '0';
          }
          else
          {
            *(field_ptr + 1) = '1';
          }
        }
      }
      else
      {

        /*
        ** signal termination of processing caused by EOF of input file
        */

        ue6_out_ptr->ue6_o_status = UE6_O_TERM;
      }
      return(0);
    }

### ADAULD Utility User Exit 7

#### Description

The Adabas ADAULD utility user exit 7 is a user exit that performs user processing on a compressed ADABAS record before it is unloaded by the ADAULD utility. The user exit may change or skip records or terminate unloading. The actions to be taken are indicated by user-exit return values that are interpreted by the ADAULD utility.

The utility user exit 7 is activated by setting the USEREXIT option in ADAULD.

#### Input Parameters

    Format: uex_7 ( in_st, out_st )

in_st: | Usage: | user exit 7 input structure
| Type: | struct ue7_in *
| Access: | read/write
| Mechanism: | by reference

out_st: | Usage: | user exit 7 output structure
| Type: | struct ue7_out *
| Access: | write
| Mechanism: | by reference

#### Return Values

The user-exit return value is returned in the output-status field.

UE7_O_PROCESS: | Unload this record.
UE7_O_SKIP: | Skip this record without unloading it.
UE7_O_TERM: | Terminate unloading of records immediately.

For the definitions of these constants, the structure ue7_in and the structure ue7_out, see the include file adauex.h.

#### Parameter Block for User Exit 7

    typedef struct ue7_in
    {
      unsigned long          ue7_i_len;        /* length of input record         */
      unsigned char*         ue7_i_ptr;        /* pointer to input record        */
    } UE7_IN;

    typedef struct ue7_out
    {

      unsigned long          ue7_o_status;
    #define UE7_O_PROCESS    1                 /* process (unload) this record)  */
    #define UE7_O_SKIP       2                 /* skip this record               */
    #define UE7_O_TERM       3                 /* terminate unload               */
    } UE7_OUT;

#### Example

    #include <adabas.h>
    #include <adauex.h>

    #define FEMALE            'F'
    #define MALE              'M'

    #define REC_LNG            2     /* Record starts with two byte length field */
    #define ISN_LNG            4     /* Next four bytes represent ISN            */
    #define PERS_ID_LNG        9     /* Next nine bytes represent personnel id   */

    #define FULL_NAME_OFFSET   (REC_LNG + ISN_LNG + PERS_ID_LNG)
                                                 /* Offset to FULL-NAME group    */
    #define EMPTY_FIELD_IND    0xC0              /* Indicator for empty NU-field */

    /*+
    **      NAME:
    **              uex_7 - adabas user exit 7 example
    **
    **      SYNOPSIS:
    **              int     uex_7 ()
    **
    **      DESCRIPTION:
    **              This USEREXIT requires compressed records
    **              of the example file EMPLOYEES as input.
    **
    **              It unloads all records of female employees and skips
    **              all other records of male employees. If a value different
    **              from 'F' or 'M' is found ADAULD is terminated.

    **
    **      RETURN VALUES:
    **              always 0
    **
    **      FUNCTIONS USED:
    **              none.
    **
    -*/

    #ifdef __STDC__

    int uex_7 (struct ue7_in* ue7_in_ptr, struct ue7_out* ue7_out_ptr)

    #else

    int uex_7 (ue7_in_ptr, ue7_out_ptr)

    UE7_IN  *ue7_in_ptr;
    UE7_OUT *ue7_out_ptr;

    #endif
    {
      register unsigned char *field_ptr;

      /*
      ** skip to first field of FULL-NAME group
      */

      field_ptr =  ue7_in_ptr->ue7_i_ptr + FULL_NAME_OFFSET;

      if (*field_ptr & EMPTY_FIELD_IND)
      {
        /*
        ** one empty NU-field (see FDT), skip to NAME-field
        */

        field_ptr += 1;
      }
      else
      {
        /*
        ** it's a length indicator, skip to NAME-field
        */

        field_ptr += *field_ptr;
      }

      field_ptr += *field_ptr;
                     /* Add length byte of NAME-field, skip to MIDDLE-NAME-field */

      if (*field_ptr & EMPTY_FIELD_IND)
      {
        /*
        ** one empty NU-field (see FDT), skip to MARRIAGE-STATE-field
        */

        field_ptr += 1;
      }
      else
      {
        /*
        ** it's a length indicator, skip to MARRIAGE-STATE-field
        */

        field_ptr += *field_ptr;
      }

      field_ptr += 1;                                        /* Skip to SEX-field */

      if (field_ptr < (ue7_in_ptr->ue7_i_ptr + ue7_in_ptr->ue7_i_len))
      {
        if (*field_ptr == FEMALE)
        {
            return(0);                         /* Female employee, unload record */
        }
        else if (*field_ptr == MALE)
        {
          ue7_out_ptr->ue7_o_status = UE7_O_SKIP;
          return(0);                          /* Male employee, skip this record */
        }
      }

      /*
      ** something is wrong, terminate ADAULD
      */

      ue7_out_ptr->ue7_o_status = UE7_O_TERM;
      return(0);
    }

### Nucleus User Exit 11

#### Description

The Adabas nucleus user exit 11 is a user exit that performs user processing on a direct Adabas call. The routine is called when the processing of a command begins. The input parameters that are specified enable the user exit to change the parameters of the Adabas call, or to reject the call so that the user who issued the call receives an Adabas response 22 (invalid command).

The functionality of this user exit is the same as user exit 1, but it uses the new Adabas structures of version 6.

The user exit is not allowed to change the command code or to change any of the buffer lengths that are specified in the Adabas control block. Changing any of these values causes an Adabas response 22 (invalid command) to be returned to the user who issued the command.

The nucleus user exit 11 is activated by setting USEREXITS=11 in ADANUC.

#### Input Parameters

    Format: uex_11 ( pacbx, pcb, pcq6, num_abd, patb_abd)

pacbx: | Usage: | New Adabas control block
| Type: | struct adacbx *
| Access: | read/write
| Mechanism: | by reference

For the structure of an Adabas control block, see the Command Reference Manual.

pcb: | Usage: | Old Adabas control block
| Type: | struct cb_par *
| Access: | read/write
| Mechanism: | by reference

For the structure of an Adabas control block, see the Command Reference Manual.

pcq6: | Usage: | Adabas command queue element V6
| Type: | struct v6_cq_entry *
| Access: | read
| Mechanism: | by reference

For the structure of an Adabas command queue element, see the header file adauex.h.

num_abd: | Usage: | Number of Adabas buffer descriptors (ABD)
| Type: | int
| Access: | read/write
| Mechanism: | by value

patb_abd: | Usage: | Pointer to ABD list
| Type: | char *
| Access: | read/write
| Mechanism: | by reference

For the structures of ACBX, ABD and ABD list, see the Command Reference Manual.

#### Return Values

The user-exit return value is essentially an Adabas response code.

ADA_NORMAL: | Success. The nucleus checks whether illegal changes have been made in the control block. If no illegal changes are detected, the call is processed.
Else: | Failure. The Adabas call is rejected with a response 22 (invalid command).

### Nucleus User Exit 14

#### Description

The Adabas nucleus user exit 14 is a user exit that performs user processing on a CLOG output record of version 6 layout, before it is written to the CLOG file. The user exit can shorten, extend or completely change the record. If the length or structure of the record is changed, the utility PRILOGC, which is used to print the new type of CLOGs, may not be able to output the records that are created. A warning message is issued if a user exit was active when the CLOG records were written.

The nucleus user exit 14 is activated by setting USEREXITS=14 in ADANUC.

#### Input Parameters

    Format: uex_14 ( pclx, pbuf, pcq6)

pclx: | Usage: | CLOG layout 6 output record
| Type: | struct clx_entry *
| Access: | read/write
| Mechanism: | by reference

For the structure of a CLOG layout 6 record, see the CLX_ENTRY structure definition contained in adauex.h

The length of the record is contained in the first two bytes of the CLOG record. Bytes 3 and 4, which contain information for PRILOGC, must not be changed. The nucleus restores these bytes after the call to the user-exit routine.

The original length of the user-exit input record must not be increased. Additional data may only be returned by the user exit using the additional descriptor. The length of the CLOG record returned plus the length of the additional buffer must not exceed 32763 bytes, which is the maximum record length that can be written to the CLOG. The Adabas nucleus then prints a message that contains the user-exit return code 0. The user exit is disabled and will not be called again.

If a CLOG record is to be suppressed, the user exit must set the first two bytes of the record, which contain the length, to zero.

If pclx is the 0-pointer, then it points to the UEX_INIT structure (at init call).

pbuf: | Usage: | buffer pointer
| Type: | char *
| Access: | write
| Mechanism: | by reference

pdsc is the address of a structure that describes a buffer which contains additional data for the CLOG record. The buffer is specified by length and a pointer. The information contained in the buffer is appended to the CLOG output record specified by the parameter pcl.

pcq6: | Usage: | Adabas command queue element V6
| Type: | struct v6_cq_entry *
| Access: | read
| Mechanism: | by reference

For the structure of an Adabas command queue element, see the header file adauex.h.

#### Return Values

The user-exit return value is essentially an Adabas response code.

ADA_NORMAL: | Success.
Else: | Failure. The Adabas nucleus prints a message that contains the user-exit return code. The user exit is disabled and will not be called again.

### Nucleus User Exit 21

#### Description

The Adabas nucleus user exit 21 can be used to set authentication credentials via the ADABAS Server API Functions. The routine is called when the processing of a session begins.

This routine should be used as briefly as possible. It is intended for use during the transition period, until all applications use and support the Adabas Security authentication feature.

The input parameters that are specified enable the user exit to identify the calling application by analyzing the parameters of the Adabas call and set the appropriate credentials or to reject the call so that the user who issued the call receives an Adabas response 200 (security violation).

The nucleus user exit 21 is activated by setting USEREXITS=21 in ADANUC and the environment variable ADAUEX_21.

#### Input Parameters

    Format: int uex_21 (uex21, uex_init)

uex21: | Usage: | Object Handle
| Type: | struct SECUEXStruct *
| Access: | read
| Mechanism: | by reference

For the structure of an Adabas control block, see the Command Reference Manual.

uex_init: | Usage: | Initialization Indicator
| Type: | struct uex_init *
| Access: | read/write
| Mechanism: | by reference

#### Return Values

The user-exit return value determines how the authentication processing proceeds.

SECUEX_SUCCESS: | Success. The authentication processing continues with the provided credentials.
SECUEX_FAILED: | Failure. The Adabas call is rejected with a response 200 (security violation).

#### Parameter Block for User Exit 21

    struct SECUEXStruct {

        SECUEXPrivate * privatedata;	/* For Internal Use Only */

        unsigned int  secdbid;		/* database id */
        FNR           secfnr;		/* file number */
        UQID          secuqid;		/* s-node, s-user, s-tid */

        int (*set_uid_psw)   (SECUEX * su, char * uid, char * psw);
        int (*get_acbx)      (SECUEX * su, ACBX * acbx);
        int (*is_natural)    (SECUEX * su);
        int (*is_sql_gateway)(SECUEX * su);
    };

#### Functions / Methods

The user-exit provides the following functionality to enable the identification of the Adabas session:

- `*set_uid_psw` Set credentials for session.

- `*get_acbx` Retrieve the ACBX Control Block of the session.

- `*is_natural` Determine whether call was issued by a Natural application.

- `*is_sql_gateway` Determine whether call was issued by an SQL Gateway application

Function | `*set_uid_psw` | Set credentials for session
Parameter | `SECUEX * su` | Object Handle
| `char * uid` | Reference to User ID
| `char * psw` | Reference to Password
Return Value | `SECUEX_SUCCESS` | Function completed successfully
| `SECUEX_INVALID_PARAM` | Invalid or missing object handle
| `SECUEX_INVALID_INTERNAL` | Internal Error – unexpected values
| `SECUEX_INVALID_HEADER` | Internal Error – invalid security buffer
| `SECUEX_BUFFER_OVERFLOW` | Internal Error – security buffer overflow

Function | `*get_acbx` | Retrieve the ACBX Control Block of the session
Parameter | `SECUEX * su` | Object Handle
| `char * acbx` | Reference to struct ACBX
Return Value | `SECUEX_SUCCESS` | Function completed successfully
| `SECUEX_INVALID_PARAM` | Invalid or missing object handle
| `SECUEX_INVALID_INTERNAL` | Internal Error – unexpected values

For the structure of the Adabas control block, see the Command Reference documentation.

Function | `*is_natural` | Determine whether call was issued by a Natural application
Parameter | `SECUEX * su` | Object Handle
Return Value | `SECUEX_TRUE` | Calling application is Natural
| `SECUEX_FALSE` | Calling application is not Natural
| `SECUEX_INVALID_PARAM` | Invalid or missing object handle
| `SECUEX_INVALID_INTERNAL` | Internal Error – unexpected values

Function | `*is_sql_gateway` | Determine whether call was issued by an SQL Gateway application
Parameter | `SECUEX * su` | Object Handle
Return Value | `SECUEX_TRUE` | Calling application is SQL Gateway
| `SECUEX_FALSE` | Calling application is not SQL Gateway
| `SECUEX_INVALID_PARAM` | Invalid or missing object handle
| `SECUEX_INVALID_INTERNAL` | Internal Error – unexpected values

#### Example

    #include <adauex.h>

    /*
    **  NAME:
    **      uex_21 - Adabas Security Exit Example
    **
    **  SYNOPSIS:
    **      int uex_21 ()
    **      SECUEX   *   Pointer to SECUEX Data and Methods
    **      UEX_INIT *   Pointer to UEX Initialization Mode
    **
    **  DESCRIPTION:
    **      This user exit is called before an Adabas call is processed.
    **
    **      It provides the Security credentials,
    **      which are to be used for authentication in this session.
    **
    **      Because no global variables are used, this exit flags
    **      in init call to inform the Adabas nucleus that reentrant
    **      code is being used.
    **
    **      To create a shared library that includes this user exit,
    **      the makefile can be used.
    **
    **      Call:         	make   -f makefile uex21   (Linux)
    **                     	nmake -f makefile uex21   (Windows)
    **
    **  RETURN VALUES:
    **
    **      SECUEX_SUCCESS
    **      SECUEX_FAILED
    */

    #ifdef __STDC__

    int uex_21 (SECUEX    * uex21,
                UEX_INIT  * uex_init)

    #else

    int uex_21 (uex21,
                uex_init)
    SECUEX    * uex21;
    UEX_INIT  * uex_init;

    #endif

    {
      int rc;
      if (uex21 == 0)
      {
        /*
        **  User-Exit Initialization during Nucleus Startup
        **
        **  Indicate whether the user-exit is reentrant or not
        **  - UEX_REENTRANT
        **  - UEX_N_REENTRANT
        */
        uex_init->uex_type = UEX_REENTRANT;

        return ( SECUEX_SUCCESS );
      }

      else

      {
        /*
        **  AuthN Processing - during Session Initialization
        **
        **  Provide security credentials or not
        **  This can be based on the values in ACBX and UQID values
        **  which can be retrieved as needed (optional)
        **
        **  Note:
        **  Not providing security credentials
        **  will result a security violation "unable to authenticate".
        **
        */
        ACBX  acbx;
        char uid[32];
        char psw[32];

        /*
        ** Retrieve Session-Specific information
        */

        /* ACBX values */
        rc = uex21->get_acbx (uex21, &acbx);
        if (rc != SECUEX_SUCCESS)
        {
          return( SECUEX_FAILED );
        }

       /*
        ** Reject commands from users with names starting with 'h'
        */
        if ( uex21->secuqid.tid[0] == 'h' )
        {
          return( SECUEX_FAILED );
        }

        /*
        ** Reject acess to dbid=200
        ** where users names start with 'h'
        */
        if ((acbx.acbxdbid == 200 ) && (uex21->secuqid.tid[0] == 'h'))
        {
          return( SECUEX_FAILED );
        }

        /*
        ** Set Application-Specific credentials
        */
        strcpy (uid,"uexuid");
        strcpy (psw,"uexpsw");

        /* NATURAL */
        rc = uex21->is_natural (uex21);
        if (rc == SECUEX_TRUE)
        {
          strcpy (uid,"NATuid");
          strcpy (psw,"NATpsw");
        }

        /* SQL Gateway */
        rc = uex21->is_sql_gateway (uex21);
        if (rc == SECUEX_TRUE)
        {
          strcpy (uid,"SQLuid");
          strcpy (psw,"SQLpsw");
        }

        /*
        ** Set Security Credentials: userid, password
        */
        rc = uex21->set_uid_psw (uex21, uid, psw);
        if (rc != SECUEX_SUCCESS)
        {
          return( SECUEX_FAILED );
        }
      }

      return ( SECUEX_SUCCESS );       /* provided Security Credentials */
    }

### ADALNK-Specific User Exits

#### Overview

User exits for ADALNK can be used for any application that might either request control and/or want to modify Adabas parameters (e.g. the control block) during run time.

We differ between the user exits for the classic Adabas call, i.e. adabas(), and the Extended Adabas call, i.e. adabasx().

For the classic Adabas call, the user exits are called with the Adabas buffers as parameters (like the nucleus user exit 1). For the Extended Adabas call, the user exit is called with the parameters described below.

The user exit can be enabled before the Adabas call is passed to the nucleus, and after the Adabas call has been executed. The difference to the nucleus user exit 1 is that the ADALNK-specific user exit runs in the context of the user's process.

The ADALNK-specific user exits must be present as a shared library (Linux) or as a dynamic link library (Windows). See the section Creating and Defining User Exits and Hyperexits for information about how to compile and link ADALNK-specific user exits.

#### Notes on Signal Handlers (Linux)

If ADABAS calls are used in an application-defined signal handler and ADALNK user exits are established, it is possible that the user exit for the call from the signal handler is not started. This happens if the call from the signal handler occurs when another call of the user exit is currently active.

If the signal handler aborts a user application while an ADABAS call is active, the following situations can occur:

1. User exit 0 is already called but the ADABAS call is not passed to the nucleus.

2. The nucleus returns the results of the ADABAS call but user exit 1 is not called.

#### Notes on Exception Handlers (Windows)

If ADABAS calls are used in an application-defined exception handler and ADALNK user exits are established, it is possible that the user exit for the call from the exception handler is not started. This happens if the call from the exception handler occurs when another call of the user exit is currently active.

If the exception handler aborts a user application while an ADABAS call is active, the following situations can occur:

1. User exit 0 is already called but the Adabas call is not passed to the nucleus.

2. The nucleus returns the results of the Adabas call but user exit 1 is not called.

#### Input Parameters

For the classic Adabas Call:

    Format:  int  lnkuex_{0 | 1} (pcb, pfb, prb, psb, pvb, pib)

See the nucleus user exit 1 for a description of the input parameters.

For the extended Adabas Call:

    Format:  int  lnkuex_acbx_{0 | 1} (NumBuf, pACBX, pABD)

##### NumBuf

Usage | Number of Attached Buffer Descriptors (ABD) in pABD
Type | Int
Access | Read
Mechanism | by value

##### pACBX

Usage | Adabas Extended Control Buffer
Type | ACBX *
Access | read/write
Mechanism | by reference

##### pABD

Usage | Array of Pointers to ABDs
Type | ABD *
Access | read/write
Mechanism | by reference

#### Return Values

The user-exit return value is essentially an ADABAS response code.

ADA_NORMAL: | Success.
Else: | Failure. The response code will be placed into the Adabas control block. In the case of lnkuex_0, or lnkuex_acbx_0, the call will return immediately to the user. If the call is an `RC' call, the response code will be set to 0.

#### Creating a Link Between ADALNK-Specific User Exits and ADALNK

In order to establish a link between the equivalent user exits and ADALNK itself, the following environment variables have to be set:

- User exit before database access inside ADALNK

        setenv LNKUEX_0 lnk_uex.so (Linux)
       setenv LNKUEX_ACBX_0 lnk_uex_acbx.so (Linux)

  or

       set LNKUEX_0=lnk_uex.dll (Windows)
       set LNKUEX_ACBX_0 lnk_uex_acbx.dll (Windows)

  Note
  The default entry function name are 'lnkuex_0(...)' for the classic Adabas call and 'lnkuex_acbx_0(...)' for the extended Adabas call.

- User exit after database access inside ADALNK

      setenv LNKUEX_1 lnk_uex.so (Linux)
       setenv LNKUEX_ACBX_1 lnk_uex_acbx.so (Linux)

  or

      set LNKUEX_1=lnk_uex.dll (Windows)
       set LNKUEX_ACBX_1 lnk_uex_acbx.dll (Windows)

  Note
  The default entry function name are 'lnkuex_1(...)' for the classic Adabas call and 'lnkuex_acbx_1(...)' for the extended Adabas call.

It is also possible to define a different entry function name for each ADALNK-specific user exit, e.g.:

     setenv LNKUEX_0 "lnk_uex.so xx_uex_0" (Linux)
    setenv LNKUEX_ACBX_0 "lnk_uex_acbx.so xx_uex_acbx_0" (Linux)
     setenv LNKUEX_1 "lnk_uex.so yy_uex_1" (Linux)
     setenv LNKUEX_ACBX_1 "lnk_uex_acbx.so yy_uex_acbx_1" (Linux)

or

     set LNKUEX_0=”lnk_uex.dll xx_uex_0” (Windows)
    set LNKUEX_ACBX_0=”lnk_uex_acbx.dll xx_uex_acbx_0” (Windows)

    set LNKUEX_1=”lnk_uex.dll yy_uex_1” (Windows)
    set LNKUEX_ACBX_1=”lnk_uex_acbx.dll yy_uex_acbx_1” (Windows)

## Hyperexits Overview

Like subdescriptors and superdescriptors, hyperdescriptors are descriptors that are created on the basis of parent fields in a file's FDT, but in the case of hyperdescriptors, the descriptor values are generated using a user-defined algorithm. In search criteria, you specify the generated hyperdescriptor values, except if a hyperdescriptor is defined with the HE option - in this case you specify the parent field value.

Hyperexits can modify the ISN for a hyperdescriptor value. It is also possible to specify ISNs belonging to a different file. Then you can perform a search on the file containing the hyperdescriptor without using a format buffer. In order to read the resulting records, you must change the file number to the file number of the file that contains the ISNs associated with the hyperdescriptor. If you use this feature, it is important that you specify the USERISN parameter for ADACMP and ADAMUP if you load such a file - otherwise the ISNs generated by the hyperexit will no longer fit.

This algorithm is implemented in a user-defined shared library or DLL called hyperexit and should be written in the C programming language. The basic output of a hyperexit function is one or more hyperdescriptor values.

The hyperexit is dynamically loaded at the startup of a utility or when it is accessed for the first time in the nucleus, and it is called each time that a hyperdescriptor value is generated, deleted or updated, or if a hyperdescriptor with HE option is used in a search command.

A hyperexit is called for the following actions:

- Initialize a hyperexit before it is used for the first time by the nucleus for one of the actions listed below, or during a utility run if a hyperdescriptor is found in a file's FDT.

- Insert record command: the hyperexit is called as an "after image call" to produce a hyperdescriptor value that is inserted into the inverted list. The appropriate exit function is called for all of the hyperdescriptors that are defined in the FDT.

  Note
  The exit function is not called if all of the hyperdescriptor's parent fields are defined with the NU/NC options and if there are no values present for the fields.

- Delete record command: the hyperexit is called as a "before image call" to produce a hyperdescriptor value that is to be deleted from the inverted list. The appropriate exit function is called for all of the hyperdescriptors that are defined in the FDT.

- Update record command: if one or more of a hyperdescriptor's parent fields is modified, the associated hyperexit is called twice (once as a "before image call" and once as an "after image call") in order to change the hyperdescriptor value in the inverted list.

- Generate a hyperdescriptor value for a search command (only for hyperdescriptors with one parent field and defined with the HE option).

A hyperexit is used by the following utilities:

- ADAINV, for the following operations:

  - inverting a new hyperdescriptor

  - reinverting/verifying a hyperdescriptor

- ADACMP: generating hyperdescriptor values if the FDT contains a hyperdescriptor specification

- ADAULD: generating hyperdescriptor values if the FDT contains a hyperdescriptor specification.

It is important that the hyperexits generate the same values for the “after image” calls as for the “before image” calls - otherwise Adabas would not be able to remove hyperdescriptor values. This means, in particular, that following a change of a hyperexit that results in different hyperdescriptor values, the affected hyperdescriptors must be reinverted.

The hyperexits can be driven with a reentrant interface or with a non-reentrant interface. For the non-reentrant interface, the hyperexit buffers for the parent field values and the generated hyperdescriptor values are placed within the user's hyperexit module. In this case, calls to hyperexits are serialized.

For the reentrant interface, the buffers are allocated within the nucleus or utility. Therefore, a reentrant hyperexit can be called in parallel if more than one command tries to access the same hyperexit; this can improve performance compared to the non-reentrant version. In the implementation of a reentrant hyperexit, variables of storage class static may be updated only during the initialization.

Tip
The Adabas kit contains example C files for a hyperexit. These are located in the subdirectory "Adabas/examples/server" of the installation directory.

For further details about how to specify a hyperdescriptor in an FDT, see FDT Record Structure, Hyperdescriptor.

## Hyperexit Control Block and Buffers

The synopsis for a hyperexit function is as follows:

    #include <adahyx.h>

    void hyx_<number> ( HYCB_ENTRY* hy_cb )

hy_cb is a pointer to the hyperexit control block; its C definition can be found in the header file adahyx.h in the subdirectory "Adabas/inc" of the installation directory.

The hyperexit control block is a structure that contains all of the information necessary for the hyperexit and the nucleus to handle hyperdescriptors. The structure is shown in the following diagram:

The following topics are covered:

- Hyperexit Control Block

- Data Buffer for an Initialization Call Repeated

- Data Buffer for a Value Generation Call

- ISN Buffer

- Index Value Buffer

- PE Index Buffer

- Format Buffer

### Hyperexit Control Block

Variable | Type | Description
--- | --- | ---
hy_structure | unsigned char | This defines a structure level for the hyperdescriptor interface. The structure may change in future, so Adabas can check if a supported version of the hyperdescriptor interface is in use. The current structure level is 2. No other structure levels are currently supported.
hy_ctype | unsigned short | This defines which type of call is performed: 0 value generation call 1 value generation call repeated 2 initialization call 3 initialization call repeated During utility initialization or when a hyperdescriptor is processed the first time in the nucleus, an initialization call is performed. If the hyperexit needs detailed information on the parent field and the hyperdescriptor definitions, it can set the hyperexit response code hy_rsp to 1, Adabas performs an initialization call repeated. If Adabas has to convert parent values to a hyperdescriptor value, it performs a value generation call. If more than one hyperdescriptor value is to be generated, the hyperexit can deliver the values in more than one call. If additional values are to be generated, the hyperexit must set hy_rsp to 1. Then Adabas performs a value-generation call repeated.
hy_context | unsigned short | This defines the context of the value-generation call: 0 before-image value 1 after-image values 2 search-buffer value Before-image values are used when descriptor values must be removed from the index. After-image values are used when descriptor values must be inserted in the index. Search-buffer values are used if a hyperdescriptor with the HE option is specified in a search criterion of a search operation.
hy_dbid | unsigned short | This defines the database that called the hyperexit.
hy_fnr | unsigned short | This defines the hyperdescriptor’s file number.
hy_hyname | char[2] | This defines the name of the hyperdescriptor.
hy_rsp | unsigned short | The response enables the hyperdescriptors hyperexit to return a success code or an error response code. The error will be converted to an Adabas nucleus response code 86 and the hyperexits value will be returned in the Additions 2 field in the control block. During an initialization call, the utility or nucleus will terminate with an error. The response codes and their meanings are as follows: 0 Success 1 Repeat call required 2-255 Reserved for Adabas >=256 User errors
hy_mode | unsigned short | This is set by the initialization call and defines whether the exit routine is re-entrant or non-reentrant (for further information see Reentrant / Non-reentrant Interface) 0 (HY_NREENTRANT): non-reentrant 1 (HY_REENTRANT): reentrant
hy_dptr | unsigned char * | Data buffer pointer.
hy_dlng | unsigned int | Data buffer length. The maximum supported length is 65535.
hy_isn |  | This is the ISN of the data record. The ISN for the hyperdescriptor value(s) can be changed. Adabas does not check whether the ISN is less than or equal to the value of the MAXISN specified for the file.
hy_iptr | unsigned int * | ISN buffer pointer.
hy_ilng | unsigned int | The ISN buffer length. The maximum supported length is 65535.
hy_icnt | unsigned int | The number of ISN values. This number of ISNs must fit into the ISN buffer: 4 * hy_icnt must be less than or equal to hy_ilng.
hy_xptr | unsigned char * | Index value buffer pointer.
hy_xcnt | unsigned int | Number of returned index values.
hy_xlng | unsigned int | Index value buffer length.
hy_pcnt | unsigned int | Number of PE indices returned in the PE index buffer. This number must be equal to hy_xcnt if the hyperdescriptor is defined with option PE. However, in a search buffer value call, the PE index buffer is ignored.
hy_plng | unsigned int | PE index buffer length.
hy_pptr | unsigned char * | PE index buffer pointer.
hy_fprt | unsigned char * | Format buffer pointer. During an initialization call, the hyperexit may supply a format buffer. This format buffer will be used to decompress the data values of the parent field into the buffer before the hyperexit is called. The user can use the format buffer to override the default format buffer.
hy_flng | unsigned int | Format buffer length.

### Data Buffer for an Initialization Call Repeated

In an Initialization Call Repeated, Adabas provides information on the parent fields and the hyperdescriptor in the data buffer. This information has the same layout as the record buffer for an LF command with command option S (for further information see Command Reference, LF command).

Bytes | Usage
--- | ---
1 - 2 | Total length of information
3 - 4 | Number of entries
5 - n | One 'F' element for each parent field
(n + 1) - m | 'H' element for the hyperdescriptor

### Data Buffer for a Value Generation Call

In the data buffer for a Value Generation Call/Value Generation Call Repeated, Adabas inserts the hyperdescriptor according to the format buffer specification in the Initialization Call / Initialization Call Repeated.

### ISN Buffer

In a Value Generation Call / Value Generation Call Repeated, there are two ways how to define the ISN associated to the hyperdescriptor values:

1. The same ISN is to be used for all hyperdescriptor values generated by this call. In this case, the ISN must be specified in hy_isn and hy_icnt must be 0.

2. Different ISNs are used for the hyperdescriptor values generated by this call. In this case, for each descriptor value generated by the call one ISN must be inserted in the ISN buffer; hy_icnt must be equal to hy_xcnt.

### Index Value Buffer

In a Value Generation Call / Value Generation Call Repeated, the hyperexit must generate the hyperdescriptor values. hy_xcnt must be set to the number of generated hyperdescriptor values. The hyperdescriptor values must be generated in the format specified in the hyperdescriptor definition.

The following examples show how the index buffer must be generated:

#### Example 1:

    H1,10,A=HYPER(1,AA)

#### Example 2:

    H2,20,A,MU=HYPER(1,MU)

For generating two hyperdescriptor values, the length of the index value buffer must be at least 40 bytes; if the maximum number of hyperdescriptor values to be generated is larger, the index value buffer must be defined accordingly larger.

### PE Index Buffer

If a hyperdescriptor is defined with option PE, the hyperdescriptor must generate the PE indices corresponding to the hyperdescriptor values in the PE Index Buffer in a Value Generation Call / Value Generation Call Repeated. The number of PE indices must be equal to the number of hyperdescriptor values generated. The PE indices are stored as one byte binary; PE indices > 255 are not supported.

However, the hyperexit cannot supply a PE index for a search-buffer value call. The PE index from the user’s search buffer will be appended in such a case.

Packed and unpacked values are checked for validity, and variable-length values are checked to ensure that they are within the maximum permitted length for their format.

The following example shows how index value buffer and PE index buffer must be generated for a hyperdescriptor defined with option PE.

#### Example:

    H3,40,A,PE=HYPER(1,P1)

For generating two hyperdescriptor values, the length of the index value buffer must be at least 80 bytes, and the length of the PE index buffer must be at least 2; if the maximum number of hyperdescriptor values to be generated is larger, the index value buffer and the PE index buffer must be defined accordingly larger.

### Format Buffer

In an Initialization Call / Initialization Call Repeated, you may supply a format buffer to be used for the decompression of the parent field values before the value generation calls of the hyperexit. The syntax for the format buffer is the same as described in Command Reference, Calling Adabas, Format and Record Buffers, Format Buffer Syntax, but there are the following restrictions for allowed field definitions:

- Only parent fields may be specified.

- If a parent field belongs to a periodic group, you may specify the periodic group count for this periodic group.

If no format buffer has been specified, Adabas assumes the following format buffer where the following format buffer elements are contained for each parent field:

- Non MU parent field not belonging to a periodic group: name

- MU parent field not belonging to a periodic group: nameC,name1-N

- Non MU parent field PA belonging to a periodic group PG: PGC,PA1-N

- MU parent field PA belonging to a periodic group PG: PGC,PA1C,PA1(1-N),PA2C,PA2(1-N),…

The following examples illustrate the use of the default format-buffer elements. The FDT shown below is used in these examples.

    01,AA,0,A
    01,MU,10,B,MU
    01,PG,PE
     02,PP,40,A
     02,PM,20,B,MU
          .
          .
          .

#### Example 1:

    H1,10,A=HYPER(1,AA)

Because the parent field AA is not an MU field and not within a periodic group, the default format buffer is:

    AA.

Required length = maximum expected value length + 1.

#### Example 2:

    H2,20,A,MU=HYPER(1,MU)

Because MU is an MU field not within a periodic group, the default format buffer is:

    MUC,MU1-N.

The required length is dependent of the maximum expected MU count; for this example with MU count 3 the number of required bytes is 31.

#### Example 3:

    H3,40,A,PE=HYPER(1,PP)

Because PP is a non MU field in a PE, the default format buffer is:

    PGC,PP1-N.

The required length is dependent of the maximum expected periodic group count; for this example with periodic group count 2 the number of required bytes is 81.

#### Example 4:

    H4,40,A,PE,MU=HYPER(1,PM)

Because the parent field is an MU field in a periodic group, the default format buffer depends on the periodic group count in this example; if the periodic group count is 2, the format buffer is:

    PGC,PM1C,PM1(1-N),PM2C,PM2(1-N).

The required length for the data buffer depends on the maximum expected periodic group count and the expected MU counts; the required length for the example data with PGC=2, PM1C=1, PM2C=2 is 63.

## Hyperexit Interfaces

- Reentrant/Non-Reentrant Interfaces

- Hyperexit Calls

### Reentrant/Non-Reentrant Interfaces

The hyperexits can be implemented with a reentrant or a non-reentrant interface.

A computer routine is called reentrant if it can be safely executed concurrently; that is, the routine can be reentered while it is already running in another thread. In the implementation of a reentrant hyperexit, variables of storage class static may be updated only during the initialization, because otherwise one thread could overwrite the data created by another thread. This also means that the calling nucleus or utility must provide the hyperexit buffers - each thread calling the hyperexit must provide its own hyperexit buffers. An exception is the format buffer; it is always provided by the hyperexit - also for the reentrant interface, because it is used only during the initialization.

For the non-reentrant interface, Adabas serializes the hyperexit calls. This serialization of hyperexit calls can decrease the performance. The hyperexit buffers used must be provided by the hyperexit in this case.

The different handling of the hyperexit buffers has the consequence that the different calls must be implemented differently for reentrant or non-reentrant hyperexits.

In the initialization call, the hyperexit states whether it is running in reentrant or non-reentrant mode. For reentrant mode, it must set the field "hy_mode" to HY_REENTRANT (for the reentrant version) . For non-reentrant mode hy_mode must be equal to HY_N_REENTRANT - this is the default.

### Hyperexit Calls

Fields in the hyperexit control block not mentioned as output parameter in the following should not be modified during a hyperexit call.

#### Initialization Call

##### Input Parameters (reentrant and non-reentrant)

hy_ctype | This value is 2 for an initialization call.
hy_dbid | The number of the database.
hy_fnr | The number of the hyperdescriptor.
hy_hyname | The name of the hyperdescriptor.

##### Output Parameters (non-reentrant)

hy_structure | The actual structure number is 2.
hy_rsp | Success code or an error response code. In particular, you can use at the init call hy_rsp=1 to initiate an “Initialization Call Repeated”. If hy_rsp > 1during an initialization call, the utility or nucleus will terminate with an error. (Response 79 - Hyperexit not available). The Nucleus Log gets the error-message: %ADANUC-W-HYERR, HYPER userexit, descriptor HY, file ..., reason=....
hy_mode | HY_N_REENTRANT
hy_dlng | Data buffer length. The data buffer must be defined large enough for the parent fields.
hy_dptr | Data buffer pointer for parent field values.
hy_flng | Own format buffer length or 0, if no format buffer provided .
hy_fptr | Own format buffer pointer or NULL, if no format buffer provided.
Format buffer | Own format buffer, optional.

##### Output Parameters (reentrant)

hy_structure | The actual structure number is 2.
hy_rsp | Success code or an error response code. In particular, you can use at the init call hy_rsp=1 to initiate an “Initialization Call Repeated”. If hy_rsp > 1during an initialization call, the utility or nucleus will terminate with an error. (Response 79 - Hyperexit not available). The Nucleus Log gets the error-message: %ADANUC-W-HYERR, HYPER userexit, descriptor HY, file ..., reason=....
hy_mode | HY_REENTRANT
hy_dlng | Data transfer buffer length. At the init call you have to set the data buffer length.
hy_xlng | Index value buffer length
hy_ilng | ISN value buffer length (0 = not used).
hy_plng | Periodic group index buffer length (0 = not used).
hy_flng | Own format buffer length or 0, if no format buffer provided .
hy_fptr | Own format buffer pointer or NULL, if no format buffer provided.
Format buffer | Own format buffer, optional.

#### Initialization Call (repeated)

If_hy_rsp was set to 1 in the initialization call, Adabas calls the hyperexit call again with hy_ctype=3. In the data buffer, Adabas returns information on the hyperdescriptor and each parent field as described above.

#### Value generation Call

##### Input Parameters (non-reentrant)

hy_ctype | 0 indicates Value Generation Call.
hy_dbid | The database ID.
hy_fnr | The file number of the file containing the hyperdescriptor.
hy_hyname | The name of the hyperdescriptor.
hy_dlng | Data buffer length.
hy_dptr | Pointer to data buffer.
hy_isn | ISN of record.
Data buffer | Parent field values.

##### Output Parameters (non-reentrant)

hy_rsp | Success code or an error response code. In particular, you can use at the value generation call hy_rsp=1 to initiate a “Value generation call repeated”. If hy_rsp > 1 the hyperexit returns an error response code. The error will be converted to an Adabas nucleus response code 86 and the hyperexit's value will be returned in the Additions 2 field in the control block.
hy_cnt | Number of index values.
hy_xlng | Length of index value buffer.
hy_xptr | Pointer to index buffer.
hy_icnt | Number of ISN values (0 = not used).
hy_ilng | ISN buffer length (0 = not used).
hy_iptr | Pointer to ISN buffer.
hy_pcnt | Number of PE indices (0 =not used).
hy_plng | Length of PE index buffer (0 = not used)
hy_pptr | Pointer to PE index buffer (NULL = not used).
Index value buffer | Hyperdescriptor values as described above.
ISN buffer | ISNs associated with each descriptor value, optional.
PE index buffer | PE indices; only if hyperdescriptor defined with option PE and no search buffer value call.

##### Input Parameters (reentrant)

hy_structure | The actual structure number is 2.
hy_ctype | After the value generation call it is 0.
hy_dbid | The number of the database.
hy_fnr | The file number of the file containing the hyperdescriptor.
hy_hyname | The name of the hyperdescriptor.
hy_dptr | Pointer to parent field values.
hy_dlng | Data transfer buffer length.
hy_isn | ISN of record.
hy_ilng | Length of ISN buffer.
hy_iptr | Pointer to ISN buffer.
hy_xlng | Length of index values buffer.
hy_xptr | Pointer to index values buffer.
hy_plng | Length of periodic counts buffer.
hy_pptr | Pointer to periodic counts buffer.

##### Output Parameters (reentrant)

hy_rsp | Success code or an error response code. In particular, you can use at the value generation call hy_rsp=1 to initiate a “Value generation call repeated”. If hy_rsp > 1 the hyperexit returns an error response code. The error will be converted to an Adabas nucleus response code 86 and the hyperexit's value will be returned in the Additions 2 field in the control block.
hy_icnt | Number of ISN values.
hy_xcnt | Number of index values.
hy_pcnt | Number of periodic count values.
Index value buffer | Hyperdescriptor values as described above.
ISN buffer | ISNs associated with each descriptor value, optional.
PE index buffer | ISNs associated with each descriptor value, optional.

#### Value Generation Call Repeated

If hy_rsp is set to 1 during a value generation call, Adabas will process the index values and then recall the hyperexit with the same data-buffer contents, (reentrant and non-reentrant), with hy_ctype=1. Then the hyperexit is able to generate more hyperdescriptors values, or to generate hyperdescriptors values for a different ISN.

## Creating and Defining User Exits and Hyperexits

The nucleus and the utilities activate a user exit by using the parameter USEREXIT (in the utilities ADACMP and/or ADAULD). If this parameter is set, the user exit is called at specific points in the processing.

Hyperexits are activated if a file in which hyperdescriptors are defined is updated.

A user exit or hyperexit is defined by performing the following steps:

1. Write the user exit or hyperexit in the C programming language. The header files adauex.h (for user exits) and adahyx.h (for hyperexits) should be used.

   The exits can be written with default function names. The convention is "uex_"/"hyx_" followed by the number of the user exit or hyperexit, e.g.

       uex_1()       /* Default name user exit 1 */
       {}

       hyx_4()       /* Default name hyperexit 4 */
       {}

   Other names can be used by setting environment variables (see 4 below).

2. Compile the source file of the user exit or hyperexit; the option for position-independent code must be used.

3. Link the user exit or hyperexit as a shared library. The linker options used to create a shared library are machine-dependent.

4. Make the user exit or hyperexit available to Adabas by connecting the shared library with an environment variable. You may specify either the member name of the shared library, if the directory containing the shared library is contained in the LD_LIBRARY_PATH (Linux) or PATH (Windows), or you may specify the absolute path of the shared library. The environment variable is "ADAUEX_" (for the user exit) or "ADAHYX_" (for the hyperexit) followed by the number of the user exit or hyperexit, e.g.

   In csh:

       setenv ADAUEX_1 userex1.sl  # connect user exit 1 (see note below)
       setenv ADAHYX_4 $ADADATADIR/exits/hypex4.sl   # connect hyperexit 4 (see note below)

   Note: Depending on the Linux derivative used, the shared library extension is "sl" or "so".

   In sh or ksh:

       ADAUEX_1=userex1.sl
       export ADAUEX_1

   For Windows:

       set ADAUEX_1=userex1.dll  # connect user exit 1
       set ADAHYX_4=%ADADATADIR%\exits\hypex4.dll   # connect hyperexit 4

   For the sake of convenience, the default function names for the user exit/hyperexit can be overwritten, e.g.

       my_uex_1 ()
       {}

       nga_hyx_4 ()
       {}

       setenv ADAUEX_1 "userex1.sl my_uex_1" (Linux platforms)
       setenv ADAHYX_4 "$ADADATADIR/exits/hypex4.sl nga_hyx_4"

       set ADAUEX_1=userex1.dll;my_uex_1 (Windows)
       set ADAHYX_4=%ADADATADIR%\exits\hypex4.dll;nga_hyx_4

   If the nucleus cannot find the exit as specified in the environment variables, it continues searching as described in the following step.

5. The use of the ADAHYX environment variable can be omitted if the hyperexit shared libraries are located in the default database directory, with the following naming convention:

   #### Linux platforms:

       $ADADATADIR/db<xxx>/adahyx_<i>.<ext>

   where xxx is the database id, i is the hyperexit number, and ext is the shared library extension ("sl" or "so").

   #### Windows:

       %ADADATADIR%\db<xxx>\adahyx_<i>.dll

   where xxx is the database id, i is the hyperexit number.

   #### Example (Linux):

       $ADADATADIR/db076/adahyx_1.sl

   #### Example (Windows):

       %ADADATADIR%\db076\adahyx_1.dll

   In order to load a shared library, Adabas first takes the corresponding ADAHYX environment variable. If this is not present, Adabas then searches in the default database directory ($ADADATADIR/db<xxx> or %ADADATADIR%\db<xxx>).

The Adabas kit contains the required C header files, example sources for user exits and hyperexits and a corresponding makefile. Because the ADALNK user exits may be used on a different platform than the server platform, the ADALNK user exit, the corresponding C header file and makefile are also provided with Entire Net-Work (see the Entire Net-Work documentation for more information).

#### Linux Platforms

The required C header files are located located in the directories $ADAPROGDIR/inc and $ACLDIR/$ACLVERS/inc - nucleus and utility user exits need the include file adauex.h, ADALNK user exits need lnkuex.h and hyperexits need adahyx.h.

Example source files for nucleus user exit 1, nucleus user exit 2, nucleus user exit 4, ADACMP user exit 6, ADAULD user exit 7 and hyperexit 1 and the corresponding makefile are located in $ADAPROGDIR/examples.

Enter the following in order to build one of these user exit examples:

    cd  $ADAPROGDIR/examples

    make target

where target is one of the following:

User exit/hyperexit | Example source file name | target
--- | --- | ---
Nucleus user exit 1 | adauex1.c | uex1
Nucleus user exit 2 | adauex2.c | uex2
Nucleus user exit 4 | adauex4.c | uex4
ADACMP user exit 6 | adauex6.c | uex6
ADAULD user exit 7 | adauex7.c | uex7
Hyperexit 1 | adahyx1.c | hyx1

The shared library for the user exit or hyperexit is created in $ADAPROGDIR/examples/server.

An example source file for ADALNK user exit 0 and ADALNK user exit 1 (file name: lnkuex.c) and the corresponding makefile are located in $ACLDIR/examples.

Enter the following in order to build this user exit example:

    cd  $ACLDIR/examples/client

    make lnkuex

The shared library for the user exit is created in $ACLDIR/examples.

#### Windows Platforms

The required C header files are located in the directories %ADAPROGDIR%\inc and %ACLDIR%\inc - nucleus and utility user exits need the include file adauex.h, ADALNK user exits need lnkuex.h and hyperexits need adahyx.h.

Example source files for nucleus user exit 1, nucleus user exit 2, nucleus user exit 4, ADACMP user exit 6, ADAULD user exit 7 and hyperexit 1 and the corresponding makefile are located in %ADAPROGDIR%\examples.

Enter the following in order to build one of these user exit examples:

    cd  %ADAPROGDIR%\examples

    nmake target

where target is one of the following:

User exit/hyperexit | target
--- | ---
Nucleus user exit 1 | uex1
Nucleus user exit 2 | uex2
Nucleus user exit 4 | uex4
ADACMP user exit 6 | uex6
ADAULD user exit 7 | uex7
Hyperexit 1 | hyx1

An example source file for ADALNK user exit 0 and ADALNK user exit 1 (file name: lnkuex.c) and the corresponding makefile are located in %ACLDIR%\examples.

Enter the following in order to build this user exit example:

    cd  %ACLDIR%\examples

    nmake lnkuex

The DLL for the user exit or hyperexit is created in %ACLDIR%\examples.

### New Hyperexits while Nucleus is Active

A new hyperexit can be activated via a utility with the nucleus already active. This can happen

- when a new file is defined (ADAFDU),

- when a file is restored or overlaid (ADABCK),

- when a file is imported (ADAORD) or

- when a hyperdescriptor is created for an existing file with ADAINV

The nucleus initializes the hyperexit before the first value-generation call.

In the case of ADAFDU, if defining a new file and when the FDT contains a hyperdescriptor, it is possible to transfer a valid ADAHYX environment variable to the nucleus:

#### Example

    setenv ADAHYX_1 /user/adabas/hyper1.sl
    setenv FDUFDT file20.fdt
    adafdu < file20.fdu

If the ADAHYX environment variable is not specified or if a file is restored using ADABCK, the nucleus will search for the hyperexit in the location specified at nucleus startup (see above). Hence, the corresponding shared library or DLL must be moved to the appropriate directory.

### On this page

- User Exits Overview
- User Exit Descriptions
- Hyperexits Overview
- Hyperexit Control Block and Buffers
- Hyperexit Interfaces
- Creating and Defining User Exits and Hyperexits