Application Development |
While users of your application need to be notified when errors occur, it is also important to know what is happening on your servers, both during development and at runtime. Errors that occur remotely may have no meaning to a user, but in most cases, you want to determine which errors should be posted or broadcast from server to client, and what information should be displayed that will be most useful to a user of your application.
Panther provides global variables and hook functions to help you manage errors that result from requests made to a database. Default error handlers are installed to log errors on your server from Panther's database drivers and from the database engine. In addition, you can write (in JPL or C) and install customized error handlers. With a single JPL procedure, you can change the way errors are handled and control which messages are logged.
This chapter discusses:
Default Error Handlers |
The behavior of the default error handlers depends on where the database interaction occurs, that is, on which agent (client or server) and whether, particularly for servers, the application is in development or production.
Figure 37-1 By default, database errors are logged on the server. The application client outputs database errors only if database calls were made directly from client to database.
When database requests are submitted to the database via a service request from an application server, error processing takes place on the server. Therefore, there is no direct output to the client. To ensure that your application reports these errors, error handlers are installed on the server at initialization. The handlers let you monitor the results of DBMS events on the server by logging server activity to a central event log. Depending on the outcome, you might also want to display pertinent information on the client by including status/error information with service call results (refer to page 26-1 for information on displaying messages to a user).
If calls are made directly to a database from the client, the Panther default hook function provides output directly to the user.
Panther installs different default handlers for the development environment and for your production application. The handlers log messages to the central event log. One handler logs each DBMS
command, the other logs errors if they occur as the result of DBMS
commands.
The default development handler for the DBMS ONENTRY function is sm_tp_dbms_cmd_log
, which logs each DBMS
command. To minimize overhead and since no logging of commands is required at runtime, no handler is installed for production applications.
The default development and production error handler for the DBMS ONERROR function is sm_tp_dbms_error_print_all
which logs all DBMS
command errors to the central event log.
You can override the default handlers by installing your own function to handle errors. The application can also install an exit function to process all error and status information and to display this information in the application as well as log it to the central event log. Writing and installing your own handler is covered later in this chapter.
Panther installs a default error handler which is used when executing DBMS
commands directly from the client to a database, that is, without access to the request broker. In general, direct access to the database is not recommended in three-tier architecture since your application cannot take advantage of three-tier features, such as routing, during basic client/server processing.
If an error occurs, the default error handler displays the following information in a dialog box:
Figure 37-2 Sample error message from the client's default error handler.
For this type of error, the default error handler returns a -1 to its caller. If an error occurs while executing JPL, Panther aborts the JPL procedure where the error occurred. An aborted JPL procedure always returns An application can override the default handler by installing its own function to handle errors. It can also install an exit function to process all error and status information and to display this information in the application.
-1
to its caller.
Variables for Logging Error and Status Information |
Panther supplies several predefined variables where it stores database error and status data for the application. These global variables (begin with the characters @dm
) are automatically defined at initialization and maintained by Panther.
Before executing a DBMS
statement, Panther clears the contents of all DBMS global variables. After executing a DBMS
statement, Panther updates these variables with any error, warning or status information returned by the engine.
In addition to engine-specific codes and messages, Panther also supplies engine-independent codes and messages. These messages are defined in dmerror.h
.
The variables and their values are available in JPL and in C via Panther library functions like sm_n_getfield and sm_n_fptr.
For more information on these variables, refer to page 12-1 in the Programming Guide.
Database Error Event Functions |
Panther provides the following database-specific error event functions which are invoked when specific database events occur:
Called before executing any | |
Called after executing any | |
Called if an error occurs while executing any |
The error event functions receive three arguments:
DBMS
or DBMS SQL
.
clause, the argument identifies this engine. If no WITH
clause is used, the argument identifies the default engine.
DBMS
command from JPL or C, Panther executes the application's installed ONENTRY
function. An ONENTRY
function is useful for logging or debugging statements. The default handler for development servers is sm_tp_dbms_cmd_log
which logs each command to the central event log.
If you are supplying your own ONENTRY
function, you can also use it to modify the Panther environment, for instance, to remap cursor control keys or change protection-type properties on widgets on client screens with a direct connection to a database.
DBMS
command from JPL or C, Panther executes the application's installed ONEXIT
function. An ONEXIT
function is useful for logging or debugging statements. This function is also useful for checking error and status codes after each command.
If you are supplying a custom ONEXIT
function, you can use it to modify the Panther environment, for instance, to remap cursor control keys or change protection-type properties on widgets on client screens with a direct connection to a database.
DBMS
command from JPL or C, Panther executes the application's installed ONERROR
function. All errors are logged to the event log with the default handler sm_tp_dbms_error_print_all
. An ONERROR
function can log the values of the global DBMS error variables. It might also log the text of the command that failed.
If the error occurred while executing a command from JPL, the ONERROR
function determines whether control is returned to the procedure or to the procedure's caller.
If you are using JPL, it is recommended that you install an ONERROR
function. This ensures consistent error handling throughout the application and reduces the amount of code needed to handle errors. If an ONEXIT function is also installed, Panther calls the ONEXIT
function before the ONERROR
function.
You can write database error event functions in JPL or C.
A JPL error event function is installed as follows:
DBMS { ONENTRY | ONEXIT | ONERROR } JPL entryPoint
where entryPoint
is an entry point to a JPL module. The entry point can be a procedure name, a file name, or the name of your custom error handler. Refer to the JPL section of the Programming Guide for more information.
A C error event function is installed as follows:
DBMS { ONENTRY | ONEXIT | ONERROR } CALL function
where function is a prototyped function that takes three arguments: two strings and an integer. For example, the following entry in the pfuncs
structure installs myfunc
as a prototyped function that returns an integer:
static struct fnc_data pfuncs[] =
{
...
SM_INTFNC("myfunc(s,s,i)", myfunc),
...
};
For more information on installing prototyped functions, refer to page 44-9.
To turn off a custom error event function and reinstate the default handler, execute the command with no arguments. For example:
DBMS ONERROR
For more information and examples of each event function, refer to page 11-42 in the Programming Guide.
ONENTRY
function is ignored if the current command was executed from JPL. If the command was executed from C, the return code is returned to the calling function. It is recommended that this function return 0.
ONEXIT
function is ignored unless an error occurred while executing a DBMS
command using JPL. If the return code from the function is non-zero, Panther aborts the JPL procedure where the error occurred and returns -1
to the caller. If the command is executed from C, the return code is returned to the calling function.
If the application is also using an ONERROR function, the return code from the ONERROR
function overrides the return code from the ONEXIT function.
If an error occurs in Panther's database interface while executing JPL, a non-zero return code aborts the JPL procedure where the error occurred. The procedure's caller (either Panther or another JPL procedure) gains control. If the return code is 0
, the JPL procedure resumes control; Panther executes the next statement in the JPL procedure.
If an error occurs in Panther's database interface while executing a C function, the ONERROR
return code is returned to the calling function.
The return code from an ONERROR
function overrides the return code from an ONEXIT
function.
Custom Error Handlers |
It is recommended that your Panther application use an error handler. If the default handlers do not accomplish what you desire, you can write a custom error handler in JPL or C. In this way you can customize the error messages appearing in your application. You can use any of the global variables as part of an error handler. For example, it can use @dmretmsg to display a message from Panther's database driver or @dmengerrmsg to display an engine-specific error message. It might also display its own messages depending on the values in @dmretcode and @dmengerrcode.
The procedure's return code determines whether or not JPL continues or aborts the procedure it was executing.
There are two classes of errors in Panther's database drivers:
DBMS
statement—This might include: executing a DBMS
command that is not supported by the current engine, using an invalid keyword, executing a cursor that has not been declared, or failing to declare a connection before executing a DBMS
statement that requires one. These errors are detected by Panther's database driver which updates the global variables @dmretcode and @dmretmsg.
SELECT
from a non-existent table or column, inserting invalid data in a column, logging on with invalid arguments, or attempting to connect to a server that is not running. These errors are detected by the engine and passed to Panther's database driver which updates the global variables @dmretcode, @dmretmsg, @dmengerrcode, @dmengerrmsg, @dmengwarncode, and @dmengwarnmsg.
There are also Panther and JPL errors which are not a part of Panther's database driver. A JPL procedure might fail because of JPL syntax or colon preprocessing errors. If a JPL error occurs, Panther outputs an error message describing the error, the source of the JPL statement, and the statement that failed. Furthermore, it aborts the JPL procedure where such an error occurred and returns control to the procedure's caller. It is assumed that JPL and Panther errors are detected and corrected during application development. The only time that an application might need special handling for these errors is during transaction processing. For more information, refer to page 28-10.
An ONERROR function overrides Panther's default DBMS error handler. The function controls the display of error messages. If the error occurred while executing a command from JPL, the If you using JPL, install an ONERROR function. This ensures consistent error handling throughout the application and reduces the amount of code needed to handle errors. If an This procedure checks if the error is The following example illustrates how a database engine error is logged to the central event log.
ONERROR
function also determines whether control is returned to the procedure or to the procedure's caller.
ONEXIT
function is also installed, Panther calls the ONEXIT function, then the ONERROR
function.
Example
DM_ALREADY_ON
. In this case, it logs a message and returns 0. For all other errors, it checks for an engine error code. If there is an engine error, it logs the statement and engine-specific error message.
proc screen_entry
DBMS ONERROR jpl dbi_error_handler
...
return
proc dbi_error_handler (statement, engine)
if (@dmretcode == DM_ALREADY_ON)
{
msg emsg "You are already logged on."
return 0
}
if (@dmengerrcode != 0)
{
msg emsg @dmretmsg "%N" "Statement :statement" "%N" \
":engine Error :@dmengerrcode :@dmengerrmsg"
}
else
{
msg emsg "Application Error: :@dmretmsg " \
"See the DBA for assistance."
}
return 1proc dbi_error_handler(statement, engine)
{
vars message1, message2, message3
message1 = "DBMS ERROR " ## statement
message2 = "Database code " ## @dmretcode ## \
", Database message " ## @dmretmsg
message3 = "DBMS code " ## @dmengerrcode ## \
", DBMS message " ## @dmengerrmsg
log message1
log message2
log message3
// On DBMS failure, terminate service request with failure
service_return failure ()
}