Back to Contents


Exceptions

Summary:

See also: Flow Control, Fgl Errors.


Exception handling

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.


Exception Actions

There are five actions that can be executed if an exception is raised:

STOP
The program is immediately terminated. A message is displayed to the standard error with the location of the related statement, the error number, and the details of the exception.
CONTINUE
The program continues normally (the exception is ignored).
CALL name
The function name is called by the runtime system. The function can be defined in any module, and must have zero parameters and zero return values. The STATUS variable will be set to the corresponding error number.
GOTO name
The program execution continues at the label identified by name.
RAISE
This statement instructs the DVM that an exception raised will not be handled by the local function, but by the calling function. If an exception is raised, the current function will return and the exception handling is left to the caller function.

Exception Types

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.

Exception Classes

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

WHENEVER

The WHENEVER instruction defines exception handling in a program module, by associating an exception class with an exception action.

Syntax:

WHENEVER [ANY] ERROR { CONTINUE | STOP | CALL function | RAISE | GOTO label }

Notes:

  1. function can be any function name defined in the program.
  2. label can be any label defined in the current module.
  3. Exception classes ERROR and SQLERROR are synonyms (compatibility issue).
  4. Actions for classes ERROR, WARNING and NOT FOUND can be set independently.

Tips:

  1. For SQL instructions that can potentially generate errors, it is recommended that you define an exception handler locally; errors in the rest of the program can be handled by the default exception handler. See example 2 for more details.

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.


TRY - CATCH pseudo statement

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 CATCH
02 TRY
03     -- fgl-statements
04 CATCH
05     -- fgl-statements catching the error
06 END TRY
01 -- traditional fgl using WHENEVER ERROR GOTO
02 WHENEVER ERROR GOTO catch_error
03 -- fgl-statements
04 GOTO no_error
05 LABEL catch_error:
06 WHENEVER ERROR STOP
07 -- fgl-statements catching the error
08 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.


Handing SQL Errors

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 MAIN
02
03   DATABASE stores
04
05   WHENEVER ERROR CONTINUE
06   SELECT COUNT(*) FROM customer
07   IF sqlca.sqlcode THEN
08      ERROR "SQL Error occurred:", sqlca.sqlcode
09   END IF
10   WHENEVER ERROR STOP
11
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.


Tracing exceptions

Exceptions will be automatically logged in a file by the runtime system if all the following conditions are true: Each log entry contains:

Examples

Example 1:

01 MAIN
02   WHENEVER ERROR CALL error_handler
03   DATABASE stores
04   SELECT dummy FROM systables WHERE tabid=1
05 END MAIN
06
07 FUNCTION error_handler()
08   DISPLAY "Error:", STATUS
09   EXIT PROGRAM 1
10 END FUNCTION

Example 2:

01 MAIN
02   DEFINE tabname VARCHAR(50)
03   DEFINE rowcount INTEGER
04
05   # In the DATABASE statement, no error should occur.
06   DATABASE stores
07
08   # But in the next procedure, user may enter a wrong table.
09   WHENEVER ERROR CONTINUE
10   PROMPT "Enter a table name:" FOR tabname
11   LET sqlstmt = "SELECT COUNT(*) FROM " || tabname
12   PREPARE s FROM sqlstmt
13   IF sqlca.sqlcode THEN
14      ERROR "SQL Error occurred:", sqlca.sqlcode
15   END IF
16   EXECUTE s INTO rowcount
17   IF sqlca.sqlcode THEN
18      ERROR "SQL Error occurred:", sqlca.sqlcode
19   END IF
20   WHENEVER ERROR STOP
21
22 END MAIN

Example 3:

01 MAIN
02     TRY
03         DATABASE invalid_database_name
04         DISPLAY "Will not be displayed"
05     CATCH
06         DISPLAY "Exception caught, status = ", status USING "----&"
07     END TRY
08 END MAIN

Example 4:

01 MAIN
02     DEFINE i INTEGER
03     WHENEVER ANY ERROR CALL foo
04     TRY
05         DISPLAY "Next exception should be handled by the CATCH statement"
06         LET i = i / 0
07     CATCH
08         DISPLAY "Exception caught, status = ", status USING "----&"
09     END TRY
10     -- The previous error handler is restored after the TRY - CATCH block
11     LET status = 0
12     DISPLAY "Next exception should be handled by the foo function"
13     LET i = i / 0
14 END MAIN
15
16 FUNCTION foo()
17     DISPLAY "foo called, status = ", status USING "----&"
18 END FUNCTION

Example 5:

01 MAIN
02     DEFINE i INTEGER
03     WHENEVER ANY ERROR CALL exception_handler
04     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 STOP
08 END MAIN
09
10 FUNCTION do_exception(a, b)
11     DEFINE a, b INTEGER
12     WHENEVER ANY ERROR RAISE
13     RETURN a / b
14 END FUNCTION
15
16 FUNCTION exception_handler()
17     DISPLAY "Exception caught, status = ", status USING "----&"
18 END FUNCTION