Associate a user-defined error structure with a callback

To associate a user-defined error structure with the registered callback, specify the address of the structure as the fourth argument of mi_register_callback() function. The call to mi_register_callback() initializes the fourth parameter of the exception callback with a pointer to the user-defined structure.

For more information, see Initializing a callback.

Server only

The following func1() UDR registers a callback named excpt_callback2(), which puts error information in the DB_ERROR_BUF user-defined structure (which A sample user-defined error structure defines):
void func1(flag)
   mi_integer flag;
{
   MI_CONNECTION *conn;
   MI_CALLBACK_HANDLE *cback_hndl;
   DB_ERROR_BUF error;

   /* Initialize information in the error buffer */
   error.sqlstate[0] = '\0';
   strcpy(error.error_msg, 
      "func3: initialized error buffer.");

   /* Obtain connection descriptor */
   conn = mi_open(NULL, NULL, NULL);
   if ( conn == NULL )
      mi_db_error_raise(NULL, MI_EXCEPTION, 
         "func1: mi_open() call failed!");

   /* Register the exception callback */
   cback_hndl = mi_register_callback(conn, MI_Exception,
         excpt_callback2, (void *)&error), NULL):

   /* Execute SQL statement */
      mi_exec(conn, "bad SQL statement", MI_QUERY_NORMAL);

   /* Execution does not reach this point if the
    * excpt_callback2() callback returns MI_CB_CONTINUE.
    */
The call to mi_register_callback() specifies the address of the user-defined structure as its fourth argument. This structure is, in turn, passed in as the third argument of the excpt_callback2() callback (see Initializing a callback). The following code implements the excpt_callback2() callback function:
MI_CALLBACK_STATUS
excpt_callback2(event_type, conn, event_info, user_data)
   MI_EVENT_TYPE event_type;
   MI_CONNECTION *conn;
   void *event_info;
   void *user_data; /* user-defined error buffer gets
                    * passed here
                    */
{
   DB_ERROR_BUF *user_info;
   mi_integer state_type;
   mi_string *msg;

   user_info = ((DB_ERROR_BUF *)user_data);
   user_info->error_type = event_type;

   if ( event_type != MI_Exception )
      {
      user_info->sqlstate[0] = '\0';
      sprintf(user_info->error_msg,
         "excpt_callback2 called with wrong event type ",
          "%d", event_type);
      }
   else /* event_type is MI_Exception */
      {
      mi_error_sql_state((MI_ERROR_DESC *)event_info,
         user_info->sqlstate, 6);
      mi_errmsg((MI_ERROR_DESC *)event_info,
         user_info->error_msg, MSG_SIZE-1);
      }

   return MI_CB_EXC_HANDLED;
}
Important: Make sure that you allocate the user-defined error structure with a memory duration that is compatible with the callback that uses it. Memory durations longer than PER_COMMAND exist for use with end-of-statement, end-of-transaction, and end-of-session callbacks. However, these longer memory durations must be used only in special cases.

Client only

The following code fragment from a client LIBMI application registers a callback named clntexcpt_callback2(), which puts error information in the DB_ERROR_BUF user-defined structure (which A sample user-defined error structure defines).
int main (argc, argv)
   int argc;
   char **argv;
{
   MI_CONNECTION *conn = NULL;
   char stmt[300];
   MI_CALLBACK_HANDLE callback_hdnl;
   DB_ERROR_BUF error_buff;
   mi_integer ret;

   /* Open a connection to the database server */
   conn = mi_open(argv[1], NULL, NULL);
   if ( conn == NULL )
      /* do something appropriate */

   /* Register the exception callback, with the user-defined
    * error structure as the fourth argument to
    * mi_register_callback()
    */
   callback_hndl = mi_register_callback(conn, MI_Exception,
      (MI_VOID *)clntexcpt_callback2;
      (MI_VOID *)&error_buff, NULL);
   if ( callback_hndl == NULL )
      /* do something appropriate */
   ...
   /* Execute the SQL statement that 'stmt' contains */
   ret = send_statement(conn, stmt);
   /* If an exception occurred during the execution of the
    * SQL statement, the exception callback initialized the
    * 'error_buff' structure. Obtain error information from
    * 'error_buff'.
    */
   if ( ret == MI_ERROR )
      {
      if ( error_buff.error_type == MI_Exception )
         {
         if ( error_buf.error_level == MI_EXCEPTION )
            {
            fprintf(stderr, "MI_Exception: level = %d",
               error_buff.error_level);
            fprintf(stderr, "SQLSTATE='%s'\n",
               error_buff.sqlstate);
            fprintf(stderr, "message = '%s'\n",
               error_buff.error_msg);
            /* discontinue processing */
            }
         else /* error_level is MI_WARNING */
            {
            sprintf(warn_msg, "WARNING: %s\n", 
               error_buf.error_msg);
            display_msg(warn_msg);
            }
         }
      /* do something appropriate */
   ...
}
The call to mi_register_callback() specifies the address of the user-defined structure as its fourth argument. This structure is, in turn, passed in as the fourth argument of the clntexcpt_callback2() callback. The following code implements the clntexcpt_callback2() callback function.
void clntexcpt_callback2(event_type, conn, event_info,
      error_info)
   MI_EVENT_TYPE event_type;
   MI_CONNECTION *conn;
   void *event_info;
   void *error_info; /* user-defined error buffer here */
{
   DB_ERROR_BUF *error_buf = (DB_ERROR_BUF *)error_info;

   /* Fill user-defined structure with error information */
   error_buf->error_type = event_type;
   if ( event_type == MI_Exception )
      {
      error_buf->error_level = mi_error_level(event_info);
      mi_error_sql_state(event_info, error_buf->sqlstate, 6);
      mi_errmsg(event_info, error_buf->error_msg, MSG_SIZE-1);
      }
   else
      fprintf(stderr,
         "Warning! clntexcpt_callback() fired for event ",
         "%d", event_type);
   return;
}

The clntexcpt_callback() function is an example of an exception callback for a client LIBMI application. This callback returns void because the client LIBMI does not interpret the MI_CALLBACK_STATUS return value, as does the database server for UDRs.