Updated Status Vector - Design Specification

See also: Functional Specification

High Level Design

In versions of InterBase prior to 6.0, a status vector could only report back error messages to the client. These error messages were restricted to the JRD message facility. Because of this limitation, external services (i.e. GBAK, GFIX, etc.) could not easily return the proper error codes. To fix this, the error codes will be changed to incorporate the following information:

  • Message facility
  • Index into the message facility (i.e. the error code)
  • Mask representing an ISC error message

Since this information will be part of the status code, it will be possible to have the client interpret messages that

  • are not JRD messages
  • are not ISC messages

this allows external services and other functions to return error messages that can be more specific in nature.

High Level Algorithm

The updated status vector has two major features to it; error codes from multiple facilities and warning information. This design specification will address both features.

Data Structures/Class Hierarchy

There are no external data structures or functions defined for this feature.

Interfaces

ERR_post_warning defined in err_proto.h. This function is used to add a warning to the status vector. Warnings will always be added to the end of the vector after all errors. ERR_post will be modified to ensure that all errors come before warnings.

Detailed Design

Internal Data Structures

There are no new internal data structures for this feature, there are, however macros which encode the status information with the proper masks:

#define ISC_MASK    0x14000000    /* Defines the code as a valid ISC code */
#define FAC_MASK    0x00FF0000    /* Specifies the facility where the code is located */
#define CODE_MASK   0x0000FFFF    /* Specifies the code in the message file */

#define ENCODE_ISC_MSG(code, facility)    ((facility & 0x1F) << 16) | \
                                          ((code & 0x3FFF) << 0) | \
                                          (ISC_MASK)

#define GET_FACILITY(code)        (code & FAC_MASK) >> 16
#define GET_CODE(code)            (code & CODE_MASK) >> 0

For warning information, the following is defined in ibase.h

#define      isc_arg_warning    18

Detailed Algorithm

Error Messages

Building the new codes

jrdcodes.e::build_iberror.h

This function now retrieves codes for all facilities.

FOR S IN SYSTEM_ERRORS CROSS N IN MESSAGES OVER NUMBER WITH N.FAC_CODE = S.FAC_CODE
  SORTED BY N.FAC_CODE, S.NUMBER

/* The only facility that is guaranteed to have all codes in system errors is JRD */

 if (last_code + 1 != N.CODE && N.FAC_CODE == 0)
     fprintf (stderr, "Warning: missing codes between %d and %d (exclusive)\n",
 last_code, (int) N.CODE);
 last_code = N.CODE;
 new_code = ENCODE_ISC_MSG(S.NUMBER, N.FAC_CODE);
 fprintf (iberror, "#define isc_%-32.32s %dL\n", S.GDS_SYMBOL, new_code);
 ++code;
END_FOR;

Since only JRD is guaranteed to have sequential public codes (keys into the message file), only messages in JRD are held to this restriction. For each code that is returned, it is converted into a valid ISC error using the macro ENCODE_ISC_MSG (defined above).

Note that since message codes can now come from any facility, the codes utility creates an additional file: msg_facs.h.

FOR F IN FACILITIES WITH ANY FAC_CODE IN SYSTEM_ERRORS OVER FAC_CODE
   fprintf (msgfac, "\t%d, \"%-10.10s\",\n", F.FAC_CODE, F.FACILITY);
END_FOR;

This file will be re-generated each time codes is run and will contain a structure (defined above) which is used by why::check_status_vector to ensure that any code in a status vector has a valid facility encoded in it (in addition to other checks outlined below).

In order to allow messages other than JRD to be interpreted correctly, they need to have an entry in the MASTER_MSG_DB.SYSTEM_ERRORS relation. To do this, the following changes were made to enter_msg.e and change_msg.e:

msgsenter_msg.e

For each message entered, you will be prompted to state whether or not this message is to be public, that is sent to the client via a status vector. If the message being entered is going to be used in a status vector, then all the rules for adding a message to JRD apply. These rules are found in the document: Adding new messages to msg.gdb. Public messages (JRD messages are always public) are added to SYSTEM_ERRORS and are indexed based on the facility and index within the facility.

msgschange_msg.e

change_msg.e allows a user to change messages in the messages database. This utility was modified so that messages which are not found in the JRD facility but are public (i.e. found in SYSTEM_ERRORS) can be updated correctly. Change_msg, however does not allow a message which was previously not found in SYSTEM_ERRORS to be transferred to SYSTEM_ERRORS.

Interpreting the new codes

Once the work to create and update the error codes has been complete, we need to ensure that they are handled properly throughout the server and client (old and new). Since older clients make some assumptions about the error codes, the REMOTE_PROTOCOL version needs to be increased. Older clients assumed the following:

  • the code was located in the JRD facility
  • the index was sequential with respect to all other codes
  • the code sent to the client contained only the index into the JRD facility for the error message (for RDB compatibility)

With the increase in the remote protocol version, the 6.0 server will continue to send the status information to older clients in the same format as it was previously sent. For new clients, the codes sent to the client will stay encrypted with the facility, index, and ISC mask.

Now that the error codes are passed correctly between the client and server, the functions gds__decode and gds__encode need to be updated to work with the new format. The code for these functions use the macros defined in msg_encode.h (defined above and in bold below)

jrdgds.c::gds__encode

STATUS API_ROUTINE gds__encode (
STATUS    code,
USHORT    facility)
{
/**************************************
*
*    g d s _ $ e n c o d e
*
**************************************
*
* Functional description
*    Translate a status codes from network format to system
*    dependent form.
*
**************************************/

if (!code)
    return SUCCESS;

return ENCODE_ISC_MSG(code, facility);
}

jrdgds.c::gds__decode

STATUS API_ROUTINE gds__decode (
STATUS    code,
USHORT    *fac)
{
/**************************************
*
*    g d s _ $ d e c o d e
*
**************************************
*
* Functional description
*    Translate a status codes from system dependent form to
*    network form.
*
**************************************/

if (!code)
    return SUCCESS;
else if (code & ISC_MASK != ISC_MASK)
    /* not an ISC error message */
    return code;

*fac = GET_FACILITY(code);
return GET_CODE(code);
}

Now, before calling gds__msg_format to retrieve the message text from the InterBase.msg file, gds__decode is called and the facility returned is passed into gds__msg_format so that it returns the proper error message. Prior to this, the JRD facility (0) was set as the facility to use when retrieving the error text.

Warning Messages

Warning messages are returned to the client via the status vector. All warning information will follow any error information. To allow for this, the following changes need to be made:

err.cERR_post:

ERR_post needs to be modified so that

  • error codes are not duplicated in the status vector. Any given error should only appear once
  • all error codes precede all warnings
  • error codes are appended to the status vector. Currently each call to ERR_post destroys any prior vector

In addition, the function ERR_post_warning will be created to post a warning to the status vector. It will ensure that the warnings are placed after all error codes but will not exit out of the server. If there is no room in the status vector to add a warning, then the function will return FALSE, otherwise it will return TRUE.

BOOLEAN DLL_EXPORT ERR_post_warning (
        STATUS    status,
      ...)
{
/**************************************
 *
 *   E R R _ p o s t _ w a r n i n g
 *
 **************************************
 *
 * Functional description
 *   Post a warning to the current status vector.
 *
 **************************************/
STATUS       *status_vector, *sv;
int  status_cnt = 0;

/* Get the status vector for the thread */
status_vector = ((TDBB) GET_THREAD_DATA)->tdbb_status_vector;
sv = status_vector;
/* Move to the end of the status vector */
while (*sv+1 != isc_arg_end)
    {
    sv++;
    status_cnt++;
    }
/* Add the warning if possible */
if (status_cnt + 3 >= ISC_STATUS_LENGTH)
   return FALSE;

*sv++ = status;
/* Add varg info here */
...
return TRUE;
}

New/Affected Modules

modified:

  • jrdwhy.c
  • jrdcodes.e
  • jrdgds.c
  • jrdgds_proto.h
  • jrdmap.c
  • jrdrdbgpas.c
  • jrdibase.h
  • jrderr.c
  • jrderr_proto.h
  • remoteprotocol.h
  • remoteserver.c
  • remotewnet.c
  • remoteinterface.c
  • remoteinet.c
  • remotespxnet32.c
  • remoteipc.c
  • remotespxwin.c
  • remotednet.c
  • remotedecnet.c
  • remoteambx.c

new:

  • msg_encode.h
  • msg_facs.h (generated by codes)

Testing Considerations

  • Ensure that older clients can interpret all status codes
  • Ensure that all warnings come after all error codes