|
To catch or handle an event, you create a C function called a callback function. In your DataBlade API module, you then register callbacks to handle recovery from events. For more information on how to register callbacks, see Registering a Callback. The DataBlade API invokes a registered (and enabled) callback when the event associated with the callback occurs.
This section describes how to create a callback function. It provides the following information:
To declare a callback function, you provide the following information:

Figure 10-2 shows the declaration of a callback function called myhandler() for use in a UDR.
When a callback function completes execution, it returns any return value that it might have to the DataBlade API, which invoked it. The data type of the callback return value depends on whether a UDR or a client LIBMI application triggered the callback.
When a user-defined routine causes a callback function to be invoked, the DataBlade API expects the callback-function return value to be one of the enumerated values of the MI_CALLBACK_STATUS data type. The MI_CALLBACK_STATUS values indicate how to continue handling the event once the callback completes. Figure 10-3 shows the valid values for the MI_CALLBACK_STATUS return type.
The milib.h header file defines MI_CALLBACK_STATUS and its return-status values.
The end-of-transaction callback on page 10-76 shows use of the MI_CB_CONTINUE status. For information on the use of these return codes in exception callbacks, see Determining How To Handle the Exception.
When a client LIBMI application causes a callback to be invoked, the DataBlade API does not expect the callback to return a status value. The client LIBMI ignores any return value from a callback that a client LIBMI application registers. Therefore, any such callbacks can return void.
In effect, the client LIBMI always assumes a MI_CB_EXC_HANDLED return status from a callback. The client LIBMI returns control to the first statement after the one that threw the event. The client LIBMI application must include code that decides how to proceed based on the failure.
If a callback returns MI_CB_CONTINUE, the client LIBMI ignores the return code because this return value does not have a meaning within a client application. Within a C UDR, you can pass an exception up to a higher level in the calling sequence because the routine executes in the context of the database server. However, a client LIBMI application does not execute in the context of the database server. Therefore, it cannot assume this general exception-handling mechanism.
For an example of a callback that a client LIBMI application registers, see the clntexcpt_callback() function in Returning Error Information to the Caller.
The MI_PROC_CALLBACK modifier on a callback definition is required for callbacks that execute with Windows NT applications. For all other operating systems, this modifier is optional. To make callbacks portable between operating systems, include the MI_PROC_CALLBACK modifier in your callback declaration.
The MI_PROC_CALLBACK modifier follows the callback return type and precedes the callback name. Figure 10-2 on page 10-19 shows the location of the MI_PROC_CALLBACK modifier in the declaration of the myhandler() callback.1fs
A callback function takes the following parameters.
When you register a callback with the mi_register_callback() function, you provide arguments for most parameters of the callback. Figure 10-4 shows how a call to mi_register_callback() provides the arguments that initialize the parameters of the myhandler() callback.
The only callback parameter that the mi_register_callback() call does not initialize is the event-type structure (the event_data parameter in Figure 10-4). For more information about event-type structures, see Obtaining Event Information.
Within the body of the callback function, you provide the code that handles a particular event or events. This section provides the following information about the body of a callback function:
A callback can call most DataBlade API functions to perform its task. Callbacks often clean up resources with such functions as mi_free(), mi_close(), and mi_lo_spec_free(). However, most callback functions cannot perform the following tasks:
The following types of callbacks are not subject to the same restrictions as other callbacks:
Specifically, these callbacks can raise an exception and they can register their own exception callbacks. If an end-of-transaction or end-of-statement callback issues a call to a DataBlade API function that generates an exception, the action taken depends on whether the callback has registered its own exception callback, as follows:
When a callback function is invoked for a particular event, the DataBlade API passes an event-type structure as the third parameter of this function. This event-type structure contains information about the event that has triggered the callback. The DataBlade API stores event information in one of the following structures based on the event type:
The following table shows the event types and the corresponding event-type structures that describe them.
The milib.h header file defines the MI_ERROR_DESC and MI_TRANSITION_DESC structures.
Using an Error DescriptorThe DataBlade API stores information about exceptions and errors in an error descriptor. An error descriptor is an MI_ERROR_DESC structure. It holds information for the MI_Exception and MI_Client_Library_Error event types. The following table summarizes the memory operations for an error descriptor.
| Default Memory Duration | Memory Operation | Function Name |
|---|---|---|
| Current memory duration | Constructor | mi_error_desc_copy() |
| Destructor | mi_error_desc_destroy() |
When an MI_Exception or MI_Client_Library_Error event occurs, the DataBlade API invokes the appropriate callback. To this callback, the DataBlade API passes an initialized error descriptor as the third callback argument. The error descriptor contains information about the MI_Exception or MI_Client_Library_Error event. Within the callback, use the accessor functions in Figure 10-5 on page 10-26 to obtain the error information from the error descriptor.
This section provides the following information about an error descriptor:
The error descriptor is an opaque structure. You must use the DataBlade API functions in Figure 10-5 to access information within it.
Figure 10-5
Each of the DataBlade API functions in Figure 10-5 requires that you pass in a pointer to a valid error descriptor.
Important: The MI_ERROR_DESC structure is an opaque structure to DataBlade API modules. Do not access its internal fields directly. Informix does not guarantee that the internal structure of MI_ERROR_DESC will not change in future releases. Therefore, to create portable code, always use the accessor functions in Figure 10-5 to obtain values from this structure.
For a sample callback that obtains information from an error descriptor, see the excpt_callback2() function in Associating with a Callback.
Creating a Copy of an Error DescriptorThe DataBlade API passes the error descriptor as an argument to the callback. Therefore, the DataBlade API allocates memory for the error descriptor when it invokes the callback and deallocates this memory when the callback exits. To preserve the error information for the calling routine, you can create a user copy of the error descriptor within the callback.
The following DataBlade API functions facilitate an error-descriptor copy.
The transition descriptor, MI_TRANSITION_DESC, stores information about a transition in the processing state of the database server. It holds information for all state-transition events, including:

The milib.h header file defines the MI_TRANSITION_DESC structure.
When a state transition event occurs, the DataBlade API invokes the appropriate callback. To this callback, the DataBlade API passes an initialized transition descriptor as the third callback argument. The transition descriptor contains the transition type that initiated the state-transition event. To obtain the transition type from the descriptor, use the mi_transition_type() function. This function returns a value of type MI_TRANSITION_TYPE to indicate the transition type of the event that occurred. For a list of valid MI_TRANSITION_TYPE values, see What Is a State-Transition Event?.
Important: The MI_TRANSITION_DESC structure is an opaque structure to DataBlade API modules. Do not access its internal fields directly. Informix does not guarantee that the internal structure of MI_TRANSITION_DESC will not change in future releases. Therefore, to create portable code, always use the mi_transition_type() accessor function to obtain the transition type from this structure.
The following code fragment uses the mi_transition_type() function to determine which action to take when it receives a state-transition event: