Home | Previous Page | Next Page   Database Access > Handling Exceptions and Events > Event-Handling Mechanisms >

Invoking a Callback

A callback function (or just 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.

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 take the following actions:

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 need to register the callback only with the mi_register_callback( ) function.

The mi_register_callback( ) function requires the following arguments.

Argument Type Description 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

Managing Memory Allocations

MI_CALLBACK_HANDLE * Must be NULL Callback Handle

These arguments initialize many of the parameters of the callback function. For more information, see Figure 57.

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.

By default, a callback remains registered until the end of the connection. For more information, see Registration Duration.

Types of Callbacks

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

Callback Type Event Type More Information
Exception callback MI_Exception Database Server Exceptions
State-transition callbacks: State-Transition Events
Savepoint callback

Commit-abort callback

Post-transaction callback

End-of-statement callback

End-of-transaction callback

End-of-session callback

State-change callback

MI_EVENT_SAVEPOINT

MI_EVENT_COMMIT_ABORT

MI_EVENT_POST_XACT

MI_EVENT_END_STMT

MI_EVENT_END_XACT

MI_EVENT_END_SESSION

MI_Xact_State_Change

Client LIBMI callback MI_Client_Library_Error Client LIBMI Errors

For a general introduction on how to write a callback function, see Callback Functions.

Connection Descriptor

The first argument of 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 user-defined routine (UDR) or a client LIBMI application.

Server Only

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 (Server) defines):

cback_hndl = mi_register_callback(NULL, MI_EVENT_END_XACT,
   endxact_callback, NULL, NULL);

The mi_register_callback( ) function requires a valid connection descriptor for the MI_Exception event type. For example, the following code fragment registers the handle_errs( ) callback:

conn = mi_open(NULL, NULL, NULL);

if ( mi_register_callback(conn, MI_Exception, handle_errs,
      NULL, NULL) == NULL )
   /* handle error */

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

For the MI_Exception event, 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 UDR. If no callback exists 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 further information on how to register an exception callback, see Exceptions in a C UDR (Server).

End of Server Only
Client Only

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 raises an exception.

End of Client Only
Callback-Function Pointer

The third argument of 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. A callback handle has the MI_CALLBACK_HANDLE data type. Use a callback handle to identify a 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 a 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, but 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 than to unregister and reregister it.

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

Retrieving a 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 change temporarily the callback that is registered for a particular event.

To change a registered callback temporarily
  1. Register the initial callback with mi_register_callback( ).

    The mi_register_callback( ) function returns a callback handle for the callback that it receives as its third argument.

  2. Perform tasks that require the event handling of the initial callback.
  3. Obtain the callback-function pointer for the initial callback with mi_retrieve_callback( ).

    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.

    The initial callback should be unregistered.

  4. Register the temporary callback with mi_register_callback( ).

    This call to mi_register_callback( ) overwrites the previous callback that was registered for the event and returns a callback handle for the temporary callback.

  5. Perform the tasks that require the event handling of the temporary callback.
  6. Restore the initial callback with mi_register_callback( ).

    Pass the saved callback-function pointer (step 3) of the initial callback as the third argument of mi_register_callback( ). The function returns a new callback handle for the initial callback.

A temporary callback is useful when C UDRs are nested and some inner function wants to trap an event type in its own way instead of in the way that the outer function provides.

For example, suppose the func1( ) function specifies the func1_callback( ) function to handle event_type events and then calls the func2( ) function, as follows:

func1(...)
{
   MI_CALLBACK_HANDLE *cback_hndl;
   ...
   /* Set callback for event_type event type in func1( ) */
   cback_hndl = mi_register_callback(conn, event_type,
      func1_callback, ...)

   /* do some stuff */
   ...
   /* call func2( ), which "inherits" func1( ) callback */
   func2( )
   ...
}

func2( )
{
   MI_CALLBACK_HANDLE *cback_hndl;
   MI_CALLBACK_FUNC *old_callback;

   /* Save func1( ) callback in 'old_callback' */
   if ( mi_retrieve_callback(conn, event_type, cback_hndl, 
         old_callback, NULL) == MI_ERROR )
      /* handle error */

   /* Set up func2( ) callback */
   mi_unregister_callback(conn, event_type, cback_hndl);
   mi_register_callback(conn, event_type, func2_callback, ...);

   /* do some other stuff */
   ...

   /* restore func1( ) callback */
   cback_hndl = mi_register_callback(conn, event_type,
      old_callback, ...)
   ...
}

By default, the database server uses the func1_callback( ) callback to handle any event_type events that occur during execution of func2( ). For the func2( ) routine to trap an event_type event in its own way, the routine must save the func1_callback( ) callback and then register its own callback for the event_type event type.

In the preceding code, the func2( ) function performs the following tasks:

  1. Saves the func1_callback( ) from the func1( ) function

    The func2( ) function passes in the func1_callback( ) callback handle (cback_hndl) to the mi_retrieve_callback( ) function, which puts the MI_CALLBACK_FUNC handle for func1_callback( ) into the old_callback argument.

  2. Registers its own callback, func2_callback( )

    The mi_register_callback( ) function registers the func2_callback( ) function for the event_type event type.

  3. Performs its own work

    Any event_type event that occurs during this work causes the database server to invoke the func2_callback( ) function.

  4. Restores the callback of the func1( ) function

    The func2( ) function uses mi_register_callback( ) again, this time to restore the func1_callback( ) as the callback for the event_type event type.

Server Only

For example, suppose the UDR func1( ) specifies the initial_cback( ) function to handle the MI_Exception event type, but the UDR requires the tmp_cback( ) callback for MI_Exception 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, to use the tmp_cback( ) callback temporarily, and then to restore initial_cback( ):

func1( )
{
   MI_CONNECTION *conn;
   MI_CALLBACK_HANDLE *initial_hndl, *tmp_hndl;
   MI_CALLBACK_FUNC initial_cbptr;

   conn = mi_open(NULL, NULL, NULL);

   /* Register the initial callback (register #1). */
   initial_hndl = mi_register(conn, MI_Exception, 
      initial_cback, NULL, NULL);

   /* Do tasks that require initial_cback( ) as callback. */
   ...
   /* Retrieve the current callback-function pointer on
    * this connection into initial_cbptr. Pass in the
    * callback handle of initial_cback( ).
    */
   mi_retrieve_callback(conn, MI_Exception, initial_hndl,
      &initial_cbptr, NULL);
   /* Register the temporary callback (register #2).
    * Callback handle for initial callback is overwritten.
    */
   tmp_hndl = mi_register_callback(conn, MI_Exception,
      tmp_cback, NULL, NULL);

   /* Do tasks that require tmp_cback( ) as callback. */
   ...
   /* Restore initial callback (register #3) */
   initial_hndl = mi_register(conn, MI_Exception,
      &initial_cbptr, NULL, NULL);

   /* Continue with tasks that require initial_cback( ) as
    * callback.
    */
   ...
}
End of Server Only
Home | [ Top of Page | Previous Page | Next Page | Contents | Index ]