informix
Informix DataBlade API Programmer's Manual
Handling Exceptions and Events

What Is Event Handling?

The event-handling mechanism provides a way for one DataBlade API module to inform another module (or another part of the same module) that an event has occurred during execution of a function. The two parts of the event-handling mechanism are as follows:

This division of event-handling responsibility allows you to put common event-handling code for a particular condition in a single location, in a callback function. Any DataBlade API module that requires the associated event handling can then register this callback function.

When an event occurs, the DataBlade API performs the event handling based on whether it finds a registered callback that can catch (or handle) the event, as follows:

Invoking a Callback

A callback function (sometimes called just a callback) is a function that you write to handle a particular event. The DataBlade API provides the following functions to handle invocation of a callback function.

Callback Task DataBlade API Function
Register a callback mi_register_callback(), mi_unregister_callback()
Enable a callback mi_enable_callback(),
Disable a callback mi_disable_callback()
Retrieve a pointer to the callback function mi_retrieve_callback()

For the DataBlade API to invoke a callback when the associated event occurs, the following conditions must be met in the DataBlade API module:

In addition, a module can save a registered callback and restore it at a later time. The following sections describe each of these topics.

Registering a Callback

For a callback to execute when its associated event occurs, you must register it with the mi_register_callback() function. When you register a callback, you:

The call to the mi_register_callback() function must occur before the statement for which you want the exception handling. If you register more than one callback to handle a particular event, all registered callbacks execute when the event occurs. The order in which these callbacks execute is not predetermined.

Tip: You do not need to register a callback function in the database with the CREATE FUNCTION statement. You only need to register the callback with the mi_register_callback() function.

The mi_register_callback() function requires the following arguments.

Argument Type Description For More Information
MI_CONNECTION * A pointer to the connection on which the callback is to be registered. It might be NULL if the connection is undefined, as is the case with some client-LIBMI errors and state-transition events. Connection Descriptor
MI_EVENT_TYPE The event type that the callback handles Types of Callbacks
MI_CALLBACK_FUNC A pointer to the callback function to invoke when the specified event occurs Callback-Function Pointer
void * A pointer to the user data, which is passed to the callback function when the specified event occurs. It can be used to pass additional information to and from the callback. Returning Error Information to the Caller Returning Information to the Caller
MI_CALLBACK_HANDLE * Must be NULL Callback Handle

These arguments initialize many of the parameters of the callback function. For more information, see Figure 10-4 on page 10-22.

When mi_register_callback() registers the callback, the function returns a callback handle for the callback. For more information, see Callback Handle.

If a callback is not registered when its event occurs, the DataBlade API takes the default behavior. For more information, see Using Default Behavior.

Types of Callbacks

The second argument to the mi_register_callback() function is the event type. The DataBlade API supports a callback on each event type. The following table lists the types of callbacks that the DataBlade API supports and the events the invoke them.

Callback Type Event Type For More Information
Exception callback MI_Exception Handling Database Server Exceptions
State-transition callbacks: Handling State Transitions
State-change callback MI_Xact_State_Change
End-of-session callback MI_EVENT_END_SESSION
End-of-statement callback MI_EVENT_END_STMT
End-of-transaction callback MI_EVENT_END_XACT
Client-LIBMI callback MI_Client_Library_Error Handling Client LIBMI Errors
All-events callback MI_All_Events Creating an All-Events Callback

For a general introduction to how to write a callback function, see Creating a Callback Function.

Connection Descriptor

The first argument to the mi_register_callback() function is a connection descriptor. This connection descriptor can be either a NULL-valued pointer or a pointer to a valid connection. The valid value depends on whether the calling module is a C UDRor a client LIBMI application.

For a UDR, the connection descriptor must be a NULL-valued pointer when you register callbacks for the following state-transition events:

For example, the following call to mi_register_callback() specifies a connection descriptor of NULL to register the endxact_callback() end-of-transaction callback, (which State Transitions In a C UDR defines):

The mi_register_callback() function requires a valid connection descriptor for all other UDR event types (MI_Exception and MI_All_Events). For example, the following code fragment registers the all_callback() all-events callback (which Creating an All-Events Callback defines):

In the preceding fragment, the mi_register_callback() function specifies a valid connection descriptor, which the mi_open() function has initialized.

For the MI_Exception and MI_All_Events events, you can also provide a NULL-valued pointer as a connection descriptor. In this case, the DataBlade API looks for callbacks registered by the function that called the C user-defined routine. If no callbacks exist for this calling function, the DataBlade API continues up the calling hierarchy looking for registered callbacks until it reaches the client application (which initially invoked the UDR). This hierarchy of callbacks takes advantage of the calling hierarchy.

For information on how to register an exception callback, see Exceptions In a C UDR.

For a client LIBMI application, you must provide a valid connection descriptor to mi_register_callback() to register callbacks for the following event types:

If the connection descriptor is not valid, the mi_register_callback() function throws an exception.

Callback-Function Pointer

The third argument to the mi_register_callback() function is a callback-function pointer. The DataBlade API stores a pointer to the location of a callback function in the MI_CALLBACK_FUNC data type. In the mi_register_callback() function, you can specify the callback function in either of the following ways:

Callback Handle

The mi_register_callback() function returns a callback handle, which accesses a registered callback within a DataBlade API module. The DataBlade API stores a callback handle in the MI_CALLBACK_HANDLE data type. Use this callback handle to identify the callback for the following tasks.

Callback Task DataBlade API Function
Enable a callback mi_enable_callback()
Disable a callback mi_disable_callback()
Retrieve a pointer to the callback function mi_retrieve_callback()
Unregister a callback mi_unregister_callback()

Tip: The last argument of the mi_register_callback() function is also a callback handle. However, this argument is reserved for future use and must currently be a NULL-valued pointer. Registration Duration

The registration of a callback survives until one of the following conditions is met:

Enabling and Disabling a Callback

A callback must be enabled for the database server to invoke it. The mi_register_callback() function automatically enables the callback that it registers. You can explicitly disable a registered callback with the mi_disable_callback() function. When you disable a callback, you suspend its invocation. You can later explicitly reenable it with the mi_enable_callback() function.

Tip: If you want to reuse a callback, it is usually less resource intensive to disable and reenable the callback then to unregister and reregister it.

Both the mi_enable_callback() and mi_disable_callback() functions take the following arguments:

Retrieving the Callback Function

The mi_retrieve_callback() function returns a callback-function pointer (MI_CALLBACK_FUNC) when you pass in a callback handle (MI_CALLBACK_HANDLE). This function is useful when a DataBlade API module needs to temporarily change the callback that is registered for a particular event.

To temporarily change a registered callback, follow these steps:

  1. Register the initial callback with mi_register_callback().
  2. The mi_register_callback() function returns a callback handle for the callback that it receives as its third argument.

  3. Perform tasks that require the event handling of the initial callback.
  4. Obtain the callback-function pointer for the initial callback with mi_retrieve_callback().
  5. Pass the callback handle for the initial callback as an argument to the mi_retrieve_callback() function. The function returns a callback-function pointer, which saves the location of the registered initial callback.

  6. Register the temporary callback with mi_register_callback().
  7. This call to mi_register_callback() overwrites the previous callback that was registered for the event. It returns a callback handle for the temporary callback.

  8. Perform the tasks that require the event handling of the temporary callback.
  9. Restore the initial callback with mi_register_callback().
  10. Pass the saved callback-function pointer (step 3) of the initial callback as the third argument to mi_register_callback(). The function returns a new callback handle for the initial callback.

For example, suppose the UDR func1() specifies the initial_cback() function to handle the MI_All_Events event type but it requires the tmp_cback() callback for MI_All_Events events during a portion of its execution. The following code fragment shows the use of mi_retrieve_callback() and mi_register_callback() to save the initial_cback() callback, temporarily use the tmp_cback() callback, then restore the initial_cback() callback:

Using Default Behavior

If a callback is not registered for a particular event, the DataBlade API uses its default behavior when this event occurs. The default event handling depends on whether the event occurs in a C UDR or a client LIBMI application.

Default Behavior In a C UDR

If an event occurs during the execution of the UDR and the UDR does not register any callback to handle this event, the DataBlade API takes one of the following default actions, based on the event type.

Event Type Default Behavior
MI_Exception An unhandled MI_MESSAGE exception does not halt execution of the current statement. The DataBlade API passes the warning to the client application and processing continues at the next statement of the UDR.
An unhandled MI_EXCEPTION exception aborts execution of the current statement in the UDR. The DataBlade API returns control to the calling module.
MI_EVENT_END_SESSION An unhandled MI_EVENT_END_SESSION event does not halt execution of the current statement. Processing continues at the next statement of the UDR.
MI_EVENT_END_STMT An unhandled MI_EVENT_END_STMT event does not halt execution of the current statement. Processing continues at the next statement of the UDR.
MI_EVENT_END_XACT An unhandled MI_EVENT_END_XACT event does not halt execution of the current statement. Processing continues at the next statement of the UDR.
MI_Xact_State_Change When received in a user-defined routine, an MI_Xact_State_Change event is treated the same as the MI_EVENT_END_XACT event.

If a UDR does not register a callback for the MI_Exception event whose exception level is MI_EXCEPTION (a runtime error), the DataBlade API aborts the UDR and returns control to the calling module, which might have been either of the following cases:

The calling module might have a registered callback (or some other method) to handle the exception. To prevent database runtime errors from aborting a UDR, use the mi_register_callback() function to register callbacks in the UDR. For more information, see Exceptions In a C UDR.

Important: Programming errors do not cause execution of callbacks. If a user-defined routine contains a serious programming error (such as a segmentation fault), execution jumps out of the routine and back to the routine manager. The routine manager attempts to make an entry in the database server message log file (online.log by default).

Default Behavior In Client LIBMI Applications

If an event occurs during the execution of a client LIBMI application and the application does not register any callback to handle the event, the client LIBMI takes one of the following default actions, based on the event type.

Event Type Default Behavior
MI_Exception The client LIBMI executes the system-default callback. The mi_default_callback() function implements this system-default callback. An unhandled MI_MESSAGE does not halt execution of the current statement. The DataBlade API passes the warning to the client LIBMI application and processing continues at the next statement of this client application. An unhandled MI_EXCEPTION aborts execution of the current statement in the client LIBMI application. The DataBlade API passes the error to the client LIBMI application and returns control to this client application.
MI_Xact_State_Change An unhandled MI_Xact_State_Change event does not halt execution of the current statement. Processing continues at the next statement of the client LIBMI application.
MI_Client_Library_Error The client LIBMI executes the system-default callback. The mi_default_callback() function implements this system-default callback.

On UNIX, the system-default callback causes the client LIBMI application to send the error or warning message to stderr in response to an unhandled event.

On Windows 95 and Windows NT, the system-default callback causes the client LIBMI to display the error or warning message in a Windows message box in response to an unhandled event.

To prevent the execution of the system-default callback, use the mi_register_callback() function to register callbacks in the client LIBMI application. For more information, see Exceptions In a Client LIBMI Application and Handling Client LIBMI Errors.


Informix DataBlade API Programmer's Manual, Version 9.2
Copyright © 1999, Informix Software, Inc. All rights reserved