Programming for Error Message Output
By default, all Ingres and forms system errors are returned to the EQUEL program, and default error messages are printed on the standard output device. As discussed in the QUEL Reference Guide, you can also detect the occurrences of errors in the program by using the inquire_ingres and inquire_frs statements. (Use inquire_frs for checking errors after forms statements. Use inquire_ingres for all other EQUEL statements.)
This section discusses an additional technique that enables your program not only to detect the occurrences of errors, but also to suppress the printing of default Ingres error messages, if you choose. The inquire statements detect errors but do not suppress the default messages.
This alternate technique entails creating an error-handling function in your program and passing its address to the Ingres runtime routines. This makes Ingres automatically invoke your error handler whenever a Ingres or a forms-system error occurs. You must declare the program error handler as follows:
int funcname (err_no)
int *err_no;
{
}
You must pass this function to the EQUEL routine IIseterr() for runtime bookkeeping using the statement:
IIseterr( funcname );
This forces all runtime Ingres errors through your function, passing the Ingres error number as an argument. If you choose to handle the error locally and suppress Ingres error message printing, the function should return 0; otherwise the function should return the Ingres error number received.
Avoid issuing any EQUEL statements in a user-written error handler defined to IIseterr, except for informative messages, such as message, prompt, sleep and clear screen, and messages that close down an application, such as endforms and exit.
The example below demonstrates a typical use of an error function to warn users of access to protected tables. This example passes through all other errors for default treatment.
int locerr( ingerr )
int *ingerr;
{
# define TBLPROT 5003
/* error number for protected table */
if (*ingerr == TBLPROT)
{
printf( "You are not authorized for this
operation.\n" );
return 0;
}
else
{
return *ingerr;
}
}
main()
## {
## ingres dbname
IIseterr( locerr );
...
## exit
## }
A more practical example would be a handler to catch deadlock errors. For deadlock, a reasonable handling technique in most applications is to suppress the normal error message and simply restart the transaction.
The following EQUEL program executes a Multi-Query Transaction and handles Ingres errors, including restarting the transaction on deadlock.
In this example, a program-defined error handler, rather than the inquire_ingres statement, detects Ingres errors. This technique allows the normal Ingres error message to be suppressed in the case of deadlock and the transaction to automatically restart without the user's knowledge.
# define err_deadlock 4700
# define err_noerror 0
int ingerr = err_noerror; /* Ingres error */
main()
## {
int errproc();
int deadlock();
## ingres "equeldb" /* set up test data */
## create item (name=c10, number=i4)
IIseterr( errproc );
for(;;)
{ /* Loop until success or fatal error */
## begin transaction /* start MQT*/
## append to item (name="Neil", number=38)
if (deadlock()) /* deadlock? */
continue; /* yes, try again */
## replace item (number=39) where item.name="Neil"
if (deadlock()) /* deadlock? */
continue; /* yes, try again */
## delete item where item.number=38
if (deadlock()) /* deadlock? */
continue; /* yes, try again */
## end transaction
break;
}
## destroy item
## exit
## }
## /*
## ** errproc
## ** - User-defined error routine for Ingres
## */
int
errproc( err_no )
int *err_no;
{
ingerr = *err_no; /* set the global flag */
/*
** If we return 0, Ingres will not print a message
*/
if (*err_no == err_deadlock)
return 0;
else
return *err_no;
}
## /*
## ** deadlock
## ** - User-defined deadlock detector
## ** - If the global error number is not ERR_DEADLOCK,
## ** it aborts the program and the transaction. If
## ** the error number is ERR_DEADLOCK, no ABORT
## ** is necessary because the DBMS will automatically
## ** ABORT an existing MQT.
## */
int
deadlock()
## {
if (ingerr) {
if (ingerr == err_deadlock)
{
ingerr = err_noerror;
/* Reset for next time */
return (1); /* Program will try again */
}
else
{
printf ("Aborting -- Error #%d\n",
ingerr );
## abort
## exit
exit( -1 );
}
}
return 0;
## }