Home | Previous Page | Next Page   Database Access > Handling Exceptions and Events > Database Server Exceptions >

Raising an Exception

If a DataBlade API module detects an error, it can use the mi_db_error_raise( ) function to raise an exception.

Server Only

In a C UDR, the mi_db_error_raise( ) function raises an exception to the database server.

End of Server Only
Client Only

In a client LIBMI application, the mi_db_error_raise( ) function sends the exception over to the database server.

End of Client Only

When the mi_db_error_raise( ) function raises an exception, the database server handles this exception in the same way it would if a database server exception occurred in a DataBlade API function. If the DataBlade API module has registered an exception callback, this call to mi_db_error_raise( ) invokes the exception callback. If no exception callback has been registered, the DataBlade API uses the default behavior for the handling of exceptions.

Specifying the Connection

The first argument to the mi_db_error_raise( ) function is a connection descriptor. This connection descriptor can be either a NULL-valued pointer or a pointer to a valid connection. Which values are valid depend on whether the calling module is a UDR or a client LIBMI application.

Server Only

In a C UDR, you can specify the connection descriptor to mi_db_error_raise( ) as either of the following values:

Raising an Exception on the Parent Connection

When you specify a NULL-valued connection descriptor to the mi_db_error_raise( ) function, this function raises the exception against the parent connection, which is the connection on which the C UDR was invoked. This connection might be a client connection or a UDR-owned connection that was passed to mi_exec( ), mi_exec_prepared_statement( ), or mi_routine_exec( ).

If the raised exception has an MI_EXCEPTION exception level, the database server aborts both the UDR and the current SQL expression. For both exception levels (MI_EXCEPTION and MI_MESSAGE), the database server passes the event message to the module on the parent connection and returns control to this module. If the UDR needs control of the exception, it must call mi_db_error_raise( ) with a pointer to the current connection descriptor. For more information, see ***.

The following example shows how the MI_EXCEPTION exception level causes the my_function( ) UDR to abort when mi_db_error_raise( ) specifies a NULL-valued pointer as its connection descriptor:

void MI_PROC_VACALLBACK my_function( )
{
   ... Processing ... 
   if ( error condition ) 
      {
      ... do any clean-up here ... 
      ret = mi_db_error_raise ((MI_CONNECTION *)NULL,
         MI_EXCEPTION, "FATAL ERROR in my_function( )!");
      }
   ... These lines never get reached ... 
}

Execution returns to the code that called my_function( ). If this code has an exception callback, this callback determines how the exception handling continues.

Raising an Exception on the Current Connection

When you specify a valid connection descriptor to the mi_db_error_raise( ) function, this function raises the exception against the specified connection. The DataBlade API invokes any callbacks that are registered for the MI_Exception event on this same connection. If a registered callback returns the MI_CB_EXC_HANDLED status, control returns to the UDR. (For more information, see Determining How to Handle the Exception.

When the my_function( ) routine registers a callback, the callback can catch the exception with an MI_EXCEPTION exception level, as the following example shows:

void MI_PROC_VACALLBACK
my_function( )
{
   conn = mi_open(NULL, NULL, NULL);
   ...
   cback_hndl = mi_register_callback(conn, MI_Exception,
      excpt_callback, NULL, NULL);
   ... Processing ... 
   if ( error condition ) 
      {
      ... do any clean-up here ... 
      ret = mi_db_error_raise (conn, MI_EXCEPTION, 
         "The excpt_callback( ) function is invoked from \
          my_function( ).");
      }
   ... These lines do get reached if excpt_callback( ) 
      returns MI_CB_EXC_HANDLED... 
}

For a sample implementation of the excpt_callback( ) function, see Figure 62.

End of Server Only
Client Only

In a client LIBMI application, you must specify a valid connection descriptor to the mi_db_error_raise( ) function. For an exception callback to be invoked when the mi_db_error_raise( ) function raises an exception, specify the same connection descriptor as the one on which the callback was registered.

For example, in the following code fragment, the call to mi_db_error_raise( ) causes the excpt_callback( ) function to be invoked when an MI_Exception event occurs:

conn1 = mi_open(argv[1], NULL, NULL);
cback_hndl = mi_register_callback(conn1, MI_Exception,
   clnt_callback, (void *)&error, NULL);
...
mi_db_error_raise(conn1, MI_EXCEPTION, 
   "The clnt_callback( ) callback is invoked.");

Both mi_register_callback( ), which registers the callback for the MI_Exception event, and mi_db_error_raise( ), which raises the MI_Exception event, specify conn1 as their connection descriptor.

End of Client Only

Specifying the Message

The message that mi_db_error_raise( ) passes to an exception callback can be either of the following types:

Passing Literal Messages

To raise an exception whose message text you provide, the mi_db_error_raise( ) function requires the following information:

When you pass the MI_MESSAGE or MI_EXCEPTION message type to the mi_db_error_raise( ) function, the function raises an MI_Exception event whose error descriptor contains the following information.

Error Descriptor Field Warning Runtime Error
Exception level
(2nd argument)
MI_MESSAGE MI_EXCEPTION
SQLSTATE value "01U01" "U0001"
Message text
(3rd argument)
Specified warning text Specified error text

For example, the following call to mi_db_error_raise( ) raises an MI_Exception event with an exception level of MI_MESSAGE, an SQLSTATE value of "01U01", and the "Operation Successful" warning message:

mi_db_error_raise(conn, MI_MESSAGE, "Operation Successful");

For the following line, mi_db_error_raise( ) raises an MI_Exception event with an exception level of MI_EXCEPTION, an SQLSTATE value of "U0001", and the "Out of Memory!!!" error message:

mi_db_error_raise(conn, MI_EXCEPTION, "Out of Memory!!!");

If any exception callback is registered for the same connection, the DataBlade API sends this error descriptor to the callback when the MI_Exception event is raised.

Server Only

If the C UDR (or any if its calling routines) has not registered an exception callback when the MI_Exception event is raised, the DataBlade API performs the default exception handling, which depends on the exception level of the exception:

End of Server Only
Client Only

If the client LIBMI application has not registered an exception callback when the MI_Exception event is raised, the client LIBMI calls the system-default callback, which provides the following information:

For more information on the actions of the system-default callback, see Using Default Behavior.

End of Client Only
Raising Custom Messages

The mi_db_error_raise( ) function can raise exceptions with custom messages, which DataBlade modules and UDRs can store in the syserrors system catalog table. The syserrors table maps these messages to five-character SQLSTATE values.

To raise an exception whose message text is stored in syserrors, you provide the following information to the mi_db_error_raise( ) function:

When you pass the MI_SQL message type to the mi_db_error_raise( ) function, the function raises an MI_Exception event whose error descriptor contains the following information:

Error Descriptor Field Warning Runtime Error
Exception level MI_MESSAGE

(If the SQLSTATE value has a class code of "01")

MI_EXCEPTION

(If the SQLSTATE value has a class code of "02" or greater)

SQLSTATE value
(3rd argument)
Specified warning value:

"01xxx"

Specified error value:

"xxxxx"

(class code of "02" or greater)

Message text Associated warning text from syserrors table Associated error text from syserrors table

If any exception callback is registered for the same connection, the DataBlade API sends this error descriptor to the callback when the MI_Exception event is raised. For example, assume that the following predefined error message is under an SQLSTATE value of "03I01" in the syserrors table:

Operation Interrupted.

The following call to mi_db_error_raise( ) sends this predefined error message to a registered (and enabled) callback that handles the MI_Exception event:

mi_db_error_raise (conn, MI_SQL, "03I01", NULL);

The exception level for this exception would be MI_EXCEPTION because any SQLSTATE value whose class code is greater than "02" is considered to represent a runtime error. If no such callback was registered (or enabled), the database server would take its default exception-handling behavior.

If the SQLSTATE value had a class code of "01", mi_db_error_raise( ) would raise a warning instead of an error. (For more information on SQLSTATE values, see SQLSTATE Status Value.) The following mi_db_error_raise( ) call raises an MI_Exception event whose exception level is MI_MESSAGE:

mi_db_error_raise(conn, MI_SQL, "01877", NULL);

When this exception is raised, execution continues at the next line after this call to mi_db_error_raise( ).

Tip:
Both of the preceding mi_db_error_raise( ) examples specify NULL as the last argument because neither of their syserrors messages contains parameter markers. For more information on parameter markers, see Specifying Parameter Markers.
Searching for Custom Messages

When the mi_db_error_raise( ) function initiates a search of the syserrors table, it requests the message in which all components of the locale (language, territory, code set, and optional modifier) are the same in the current processing locale and the locale column of syserrors.

Tip:
For more information on the columns of the syserrors system catalog table, see the chapter on the system catalog tables in the IBM Informix: Guide to SQL Reference. For more information on SQLSTATE, see SQLSTATE Status Value.

For DataBlade API modules that use the default locale, the current processing locale is U.S. English (en_us). (The name of the default code set depends upon the platform you use. For more information on default code sets, see the IBM Informix: GLS User's Guide.) When the current processing locale is U.S. English, mi_db_error_raise( ) looks only for messages that use the U.S. English locale.

Global Language Support

For DataBlade API modules that use nondefault locales, the current processing locale is one of the following locales:

For more information on the client, database server, and server-processing locales, see the IBM Informix: GLS User's Guide.

End of Global Language Support

A GLS locale name has the format ll_tt.codeset@modf, in which ll is the name of the language, tt is the name of the territory, codeset is the name of the code set, and modf is the 4-character name of the optional locale modifier. (For more information on locale names, see the IBM Informix: GLS User's Guide.) The ll_tt.codeset@modf format is the standard GLS locale name. Locale names can take other forms. However, mi_db_error_raise( ) first attempts to convert the names of the current processing locale and the syserrors locale into this standard GLS format.

The mi_db_error_raise( ) function then performs a string comparison on these two locale names. The function attempts to match a value in the locale column of syserrors with the GLS name of the current processing locale as follows:

  1. Convert the current processing locale and syserrors locale names into standard GLS names, if possible.

    If mi_db_error_raise( ) cannot map the current processing locale name to a standard name, it cannot perform the match.

  2. Match the current processing locale name with an entire locale name, if possible.

    Locate a row in syserrors whose locale column has a value that matches the full ll_tt.codeset@modf locale name.

  3. Match the current processing locale name with only the language and territory part of a locale name, if possible.

    Locate a row in syserrors whose locale column starts with the value ll_tt (only language and territory names match).

  4. Match the current processing locale name with only the language part of a locale name, if possible.

    Locate a row in syserrors whose locale column starts with the value ll (only language name matches).

  5. Match the current processing locale name with the default locale (U.S. English), if it is available.

    Locate a row in syserrors whose locale column matches the standard GLS name of the default locale.

When mi_db_error_raise( ) finds a matching locale name for the specified SQLSTATE value, it then verifies that the code set of the locale name from syserrors is compatible with the code set of the current processing locale. A compatible code set is one that is either the same as or can be converted to the current processing code set. If the two code sets are not compatible, mi_db_error_raise( ) continues to search the syserrors table for rows that match the specified SQLSTATE value. Once mi_db_error_raise( ) finds a matching row, it obtains the text from the corresponding message column of syserrors.

For example, suppose the current processing locale is the French Canadian locale, fr_ca.8859-1, and you issue the following call to mi_db_error_raise( ):

mi_db_error_raise(conn, MI_SQL, "08001", NULL);

The mi_db_error_raise( ) function performs the following search process to locate entries in syserrors:

  1. Is there a row with the sqlstate column of "08001" and a locale value that matches "fr_ca.8859-1"?
  2. Is there a row with the sqlstate column of "08001" and a locale value that starts with "fr_ca"?
  3. Is there a row with the sqlstate column of "08001" and a locale value that starts with "fr"?
  4. Is there a row with the sqlstate column of "08001" and a locale value that starts with "en_us"?

Suppose mi_db_error_raise( ) finds a row in syserrors with an sqlstate value of "08001" and a locale of "fr_ca.1250". The function obtains the associated text from the message column of this row if it can find valid code-set conversion files between the ISO8859-1 code set (8859-1) and the Microsoft 1250 code set (1250).

Server Only

For C UDRs, these code-set conversion files must exist on the server computer.

End of Server Only
Client Only

For client LIBMI applications, these code-set conversion files must exist on the client computer.

End of Client Only
Specifying Parameter Markers

The custom message in the syserrors system catalog table can contain parameter markers. These parameter markers are sequences of characters enclosed by a single percent sign on each end (for example, %TOKEN%). A parameter marker is treated as a variable for which the mi_db_error_raise( ) function can supply a value.

For messages with parameter markers, mi_db_error_raise( ) can handle a variable-length parameter list, as follows:

The mi_db_error_raise( ) function requires a parameter pair for each parameter marker in the message. A parameter pair has the following values:

Parameter pairs do not have to be in the same order as the markers in the string.

Important:
Terminate the parameter list arguments with a NULL pointer. If a NULL pointer does not terminate the list, the results are unpredictable.

The first member of the parameter pair has the following syntax:

parameter_name%format_character

The mi_db_error_raise( ) function supports following format_character values.

Format Character
Meaning
d
Integer
f,g,G,e,E
Double (by reference)
T
Text (mi_lvarchar type, that is, a pointer to mi_lvarchar)
t
Length followed by string (two separate parameters)
s
Null-terminated C string

For example, suppose that the following message is under an SQLSTATE value of "2AM10" in the syserrors table:

"Line %LINE%: Syntax error at '%TOKEN%':%CMD%"

This message contains the following parameter markers: LINE, TOKEN, and CMD. The following call to mi_db_error_raise( ) assigns the string "selecl" to the TOKEN parameter, 500 to the LINE parameter, and the text of the query to the CMD parameter in the message text:

mi_db_error_raise (conn, MI_SQL, "2AM10",
   "TOKEN%s", "selecl",
   "LINE%d", (mi_integer)500,
   "CMD%s", "selecl * from tables\;",
   NULL);

The string "TOKEN%s" indicates that the value that replaces the parameter marker %TOKEN% in the message string is to be formatted as a string (%s). The next member of the parameter pair, the string "selecl", is the value to format.

This mi_db_error_raise( ) call sends the following message to an exception callback:

"Line 500: Syntax error at 'selecl':selecl * from tables;" 
Global Language Support

The mi_db_error_raise( ) function assumes that any message text or message parameter strings that you supply are in the current processing locale.

End of Global Language Support
Adding Custom Messages

You can store custom status codes and their associated messages in the syserrors system catalog table.

To add a custom message
  1. Determine the SQLSTATE code for the message you want to add.
  2. Insert a row into the syserrors system catalog table for the new message.
Choosing an SQLSTATE Code

The syserrors system catalog table holds custom messages for DataBlade modules and UDRs. A unique SQLSTATE value identifies each row in the syserrors system catalog table. Therefore, to store a custom message in syserrors, you assign it an SQLSTATE value.

You must ensure that this SQLSTATE value is unique within syserrors. When you choose an SQLSTATE value, keep the following restrictions in mind:

You can use the following query to determine the current list of SQLSTATE message strings in syserrors:

SELECT sqlstate, locale, message FROM syserrors
ORDER BY sqlstate, locale;
Global Language Support

The locale column is used for the internationalization of error and warning messages. For more information, see Searching for Custom Messages.

End of Global Language Support
Adding New Messages

To create a new message, insert a row into the syserrors system catalog table. By default, all users can view this table, but only users with the DBA privilege can modify it. For more information on columns of the syserrors system catalog table, see the IBM Informix: Guide to SQL Reference.

For example, the following INSERT statement inserts a new message into syserrors whose SQLSTATE value is "03I01":

INSERT INTO syserrors 
VALUES ("03I01", "en_us.8859-1", 0, 1, 
   "Operation Interrupted.");
Global Language Support

Enter message text in the language of the target locale, with the characters in the locale code set. By convention, do not include any newline characters in the message. Make sure you also update the locale column of syserrors with the name of the target locale of the message text. For information on locale names, see the IBM Informix: GLS User's Guide.

Do not allow any code-set conversion to take place when you insert the message text. If the code sets of the client and database locales differ, temporarily set both the CLIENT_LOCALE and DB_LOCALE environment variables in the client environment to the name of the database locale. This workaround prevents the client application from performing code-set conversion.

If you specify any parameters in the message text, include only ASCII characters in the parameters names. Following this convention means that the parameter name can be the same for all locales. All code sets include the ASCII characters.

End of Global Language Support
Home | [ Top of Page | Previous Page | Next Page | Contents | Index ]