Summary:
See also: Flow Control, Fgl Errors.
If an instructions executes abnormally, the runtime system throws exceptions that can be handled by the program. Actions can be taken based on the class of the exception. There is no way to raise exceptions explicitly; only the runtime system can throw exceptions. Runtime errors (i.e. exceptions) can be trapped by a WHENEVER exception handler or by a TRY / CATCH block.
There are five actions that can be executed if an exception is raised:
There are four types of exceptions, defining the kind of errors that can occur:
Type | Reason | Examples |
ET_STATEMENT |
Error occurred in a statement. | DISPLAY AT invalid coordinates. |
ET_EXPRESSION |
Expression evaluation error. | Division by zero. |
ET_NOTFOUND |
An SQL statement returns status NOTFOUND. | FETCH when cursor is on last row. |
ET_WARNING |
An SQL statement sets sqlca.sqlawarn flag. | Fetched CHAR value has been truncated. |
The exception classes indirectly define the exception type:
Class | Related Exception Type (defines the error reason) | Default Action |
ERROR | ET_STATEMENT |
STOP |
ANY ERROR | ET_STATEMENT and ET_EXPRESSION |
CONTINUE |
NOT FOUND | ET_NOTFOUND |
CONTINUE |
WARNING | ET_WARNING |
CONTINUE |
The WHENEVER instruction defines exception handling in a program module, by associating an exception class with an exception action.
WHENEVER [ANY] ERROR { CONTINUE | STOP
| CALL function | RAISE
| GOTO label }
Warning: The scope of a WHENEVER instruction is similar to a C pre-processor macro. It is local to the module and valid until the end of the module, unless a new WHENEVER instruction is encountered by the compiler.
Any FGL statement in the TRY block will be executed until an exception is thrown. After an exception the program execution continues in the CATCH block. If no CATCH block is provided, the execution continues after END TRY.
Without an exception the program continues after END TRY.
TRY can be compared with WHENEVER ERROR GOTO label.
The next two code fragments have similar behavior:
01
-- Exception handling using TRY CATCH02
TRY03
-- fgl-statements04
CATCH05
-- fgl-statements catching the error06
END TRY
01
-- traditional fgl using WHENEVER ERROR GOTO02
WHENEVER ERROR GOTO catch_error03
-- fgl-statements04
GOTO no_error05
LABEL catch_error:06
WHENEVER ERROR STOP07
-- fgl-statements catching the error08
LABEL no_error
The TRY statement can be nested in other TRY statements.
The TRY statement is a pseudo statement, because it does not instruct the compiler to generate code. It is not possible to set a debugger break point at TRY, CATCH or END TRY.
After executing an SQL statement, you can query STATUS, SQLSTATE, SQLERRMESSAGE and the SQLCA record to get the description of the error. When the statement has been executed with errors, STATUS and SQLCA.SQLCODE contain the SQL Error Code. If no error occurs, STATUS and SQLCA.SQLCODE are set to zero.
You control the result of an SQL statement execution by using the WHENEVER ERROR exception handler:
01
MAIN02
03
DATABASE stores04
05
WHENEVER ERROR CONTINUE06
SELECT COUNT(*) FROM customer07
IF sqlca.sqlcode THEN08
ERROR "SQL Error occurred:", sqlca.sqlcode09
END IF10
WHENEVER ERROR STOP11
12
END MAIN
The SQL Error Codes are not standard. For example, ORACLE returns 903 when a table name does not exist.
By convention, the STATUS and SQLCA.SQLCODE variables always use IBM Informix SQL Error Codes. When using IBM Informix, both STATUS and SQLCA.SQLCODE variables contain the native Informix error code. When using other database servers, the database interface automatically converts native SQL Error Codes to IBM Informix Error Codes. If no equivalent Informix Error Code can be found, the interface returns -6372 in SQLCA.SQLCODE.
If an SQL error occurs when using IBM Informix, the SQLCA variable is filled with standard information as described in the Informix documentation. When using other database servers, the native SQL Error Code is available in the SQLCA.SQLERRD[2] register. SQL Error Codes in SQLCA.SQLERRD[2] are always negative, even if the database server defines positives SQL Error Codes. Additionally, if the target database API supports ANSI SQL states, the SQLSTATE code is returned in SQLCA.SQLERRM.
The NOTFOUND (100) execution status is returned after a FETCH, when no rows are found.
See also: Connections.
01
MAIN02
WHENEVER ERROR CALL error_handler03
DATABASE stores04
SELECT dummy FROM systables WHERE tabid=105
END MAIN06
07
FUNCTION error_handler()08
DISPLAY "Error:", STATUS09
EXIT PROGRAM 110
END FUNCTION
01
MAIN02
DEFINE tabname VARCHAR(50)03
DEFINE rowcount INTEGER04
05
# In the DATABASE statement, no error should occur.06
DATABASE stores07
08
# But in the next procedure, user may enter a wrong table.09
WHENEVER ERROR CONTINUE10
PROMPT "Enter a table name:" FOR tabname11
LET sqlstmt = "SELECT COUNT(*) FROM " || tabname12
PREPARE s FROM sqlstmt13
IF sqlca.sqlcode THEN14
ERROR "SQL Error occurred:", sqlca.sqlcode15
END IF16
EXECUTE s INTO rowcount17
IF sqlca.sqlcode THEN18
ERROR "SQL Error occurred:", sqlca.sqlcode19
END IF20
WHENEVER ERROR STOP21
22
END MAIN
01
MAIN02
TRY03
DATABASE invalid_database_name04
DISPLAY "Will not be displayed"05
CATCH06
DISPLAY "Exception caught, status = ", status USING "----&"07
END TRY08
END MAIN
01
MAIN02
DEFINE i INTEGER03
WHENEVER ANY ERROR CALL foo04
TRY05
DISPLAY "Next exception should be handled by the CATCH statement"06
LET i = i / 007
CATCH08
DISPLAY "Exception caught, status = ", status USING "----&"09
END TRY10
-- The previous error handler is restored after the TRY - CATCH block11
LET status = 012
DISPLAY "Next exception should be handled by the foo function"13
LET i = i / 014
END MAIN15
16
FUNCTION foo()17
DISPLAY "foo called, status = ", status USING "----&"18
END FUNCTION
01
MAIN02
DEFINE i INTEGER03
WHENEVER ANY ERROR CALL exception_handler04
DISPLAY "Next function call will generate an exception"05
DISPLAY "This exception should be handled by the function exception_handler"06
DISPLAY do_exception(100, 0)07
WHENEVER ANY ERROR STOP08
END MAIN09
10
FUNCTION do_exception(a, b)11
DEFINE a, b INTEGER12
WHENEVER ANY ERROR RAISE13
RETURN a / b14
END FUNCTION15
16
FUNCTION exception_handler()17
DISPLAY "Exception caught, status = ", status USING "----&"18
END FUNCTION