Register an exception callback

When the database server or a UDR raises a database server exception, the database server invokes any callbacks that handle the MI_Exception event and that the UDR has registered (and enabled) on the current connection. Use the mi_register_callback() function to register such a callback.

The following code fragment contains the same mi_exec() call as code fragment Exceptions in a C UDR (Server). However, this UDR, has_exception_handling(), registers the excpt_callback() function as an exception callback.
Figure 1: A C UDR with exception handling
#include <mi.h>

mi_integer
has_exception_handling(flag)
   mi_integer flag;
{
   static MI_CALLBACK_STATUS MI_PROC_CALLBACK
      excpt_callback();

   MI_CONNECTION      *conn = NULL;
   MI_CALLBACK_HANDLE *cback_hndl;

   /* Obtain the connection descriptor */
   conn = mi_open(NULL, NULL, NULL);

   /* Register the 'excpt_callback' function as an
   ** exception callback */
   cback_hndl = mi_register_callback(conn, MI_Exception,
      excpt_callback, NULL, NULL);

   /* Generate a syntax error that excpt_callback() will
   ** catch */
   ret = mi_exec(conn, "bad SQL statement",
      MI_QUERY_NORMAL);
   if ( ret == MI_ERROR )
      /* handle exception */
   ...
}

When the database server exception occurs in the SQL statement that mi_exec() executes, mi_exec() returns MI_ERROR and the if statement handles the exception. For a sample implementation of the excpt_callback() callback function, see A simple exception callback .

For the excpt_callback() function to be invoked for database exceptions that occur on the current connection, you must specify the connection descriptor of the current connection when you register excpt_callback(). In A C UDR with exception handling, mi_register_callback() passes the conn connection descriptor, which the mi_open() call has obtained, when it registers excpt_callback().

The mi_open() function can be resource intensive. If your UDR is likely to be executed many times in the context of a single SQL statement, you might want to cache the connection descriptor from the initial mi_open() call in an MI_FPARAM structure. After you save this descriptor, you can reuse it in subsequent invocations of the UDR.

The C UDR in following code fragment, has_exception_handling2(), saves the connection descriptor in its MI_FPARAM structure the first time it is called and obtains the saved connection descriptor on subsequent calls.
Figure 2: Caching the connection descriptor in an exception callback
mi_integer
has_exception_handling2(flag, fparam)
   mi_integer flag;
   MI_FPARAM *fparam;
{
   MI_CONNECTION *conn = NULL;
   MI_CALLBACK_HANDLE *cback_hndl;
   DB_ERROR_BUF error;

   /* Obtain the connection descriptor from MI_FPARAM */
   conn = (MI_CONNECTION *)mi_fp_funcstate(fparam);
   if ( conn == NULL ) /* first time routine is called */
      {
      /* Obtain the connection descriptor */
      conn = mi_open(NULL, NULL, NULL);

      /* Register the 'excpt_callback2() function as an
      ** exception callback on this connection */
      cback_hndl = mi_register_callback(conn,
         MI_Exception,
         excpt_callback2, (void *)&error, NULL);

      /* Save connection descriptor in MI_FPARAM */
      mi_fp_setfuncstate(fparam, (void *)conn);
      }
   ...
}

In the preceding code fragment, the has_exception_handling2() routine registers the excpt_callback2() function as its exception callback. This callback uses a user-provided buffer to store event information. As its fourth argument, the mi_register_callback() call passes a user-defined buffer named error to the exception callback.