If a DataBlade API module detects an error, it can use the mi_db_error_raise( ) function to raise an exception.
In a C UDR, the mi_db_error_raise( ) function raises an exception to the database server.
In a client LIBMI application, the mi_db_error_raise( ) function sends the exception over to the database server.
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.
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.
In a C UDR, you can specify the connection descriptor to mi_db_error_raise( ) as either of the following values:
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.
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.
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.
The message that mi_db_error_raise( ) passes to an exception callback can be either of the following types:
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.
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.
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:
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.
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:
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( ).
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.
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.
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.
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:
If mi_db_error_raise( ) cannot map the current processing locale name to a standard name, it cannot perform the match.
Locate a row in syserrors whose locale column has a value that matches the full ll_tt.codeset@modf locale name.
Locate a row in syserrors whose locale column starts with the value ll_tt (only language and territory names match).
Locate a row in syserrors whose locale column starts with the value ll (only language name matches).
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:
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).
For C UDRs, these code-set conversion files must exist on the server computer.
For client LIBMI applications, these code-set conversion files must exist on the client computer.
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.
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.
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;"
The mi_db_error_raise( ) function assumes that any message text or message parameter strings that you supply are in the current processing locale.
You can store custom status codes and their associated messages in the syserrors system catalog table.
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:
Messages that the database server provides are not stored in the syserrors system catalog table. However, any special modules that are included with the database server (such as R-tree support) might have their own messages in syserrors.
These messages are not stored in the syserrors table. For a list of the reserved values of SQLSTATE, see SQLSTATE Status Value.
To define a custom warning message, you must define an SQLSTATE value that has a "01" class code and an unused subclass code.
When a DataBlade module is installed, associated messages might be added to syserrors. Avoid the use of any SQLSTATE values that an installed DataBlade module might use. You must also take care not to delete installed messages, or they must be re-created by a restore from a backup or a reinstallation.
You can group warnings and errors for your DataBlade modules into the same class code, each with a different subclass code.
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;
The locale column is used for the internationalization of error and warning messages. For more information, see Searching for Custom 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.");
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.