DOCUMENT #692 ======================================================================= TESTING FOR ERRORS ======================================================================= PRODUCT: R:BASE VERSION : 3.1 or Higher ======================================================================= AREA : Programming In R:BASE CATEGORY: Macros & Custom Code ======================================================================= All well written programs need to be able to check and determine if key lines are executed or the proper answers are given --- and, if not, then display an error message or run alternative commands. R:BASE has three different ways to check the code for proper execution. The three ways you can process R:BASE errors in your application code are: the R:BASE ERROR VARIABLE, SQLCODE , and the WHENEVER statement. Error Variable ============== The first, and most commonly used, is the ERROR VARIABLE. The ERROR VARIABLE is a special variable defined to hold the error codes that R:BASE returns. The first step in using the error variable is to define the name of the variable. Use the command: SET ERROR VARIABLE errorvar, where errorvar is the name of the variable that contains the error code. You can name the error variable any name you want. Only one error variable is used in an R:BASE session (an R:BASE session is from when you start R:BASE until you EXIT). The error variable has a value after every command in a program or R:BASE session. The value is either 0 (successful command) or a number indicating the error that occurred on the last executed command. Because the R:BASE error variable is set after every command, when checking the errorcode the very next line after the command to be checked must test the error variable or place its value into a holding variable: SET VARIABLE vhold =.errorvar. The variable vhold is then used to determine what happens next in the program. There is only one error variable in a program (errorvar), but there can be many holding variables (vhold). Holding variables are needed because the error variable is set after every command. For example, PAUSE is a command that always executes successfully, so the error variable is always set to 0 after it. To turn off an error variable or to use one with a different name you must use the SET ERROR VARIABLE OFF command. When using an error variable do not clear it with the CLEAR VAR command. When clearing variables always use the CLEAR ALL VAR EXCEPT errorvar. You can generate other errors in your application by clearing an error variable instead of setting it off. Error codes trapped by the error variable are not only for SQL commands, but any command that can be used in R:BASE. This is different from the other techniques as they only check the commands that are SQL specific. A useful technique in identifying errors in the code is to place an IF statement based on the holding variable to redirect the flow of the code and to provide a message to the user. For example: SET ERROR VAR verror CONNECT concomp SET VAR vhold1 = .verror IF vhold1 <> 0 THEN CLS FROM 24,1 TO 24,80 RED WRITE 'Error connecting database.' AT 24,27 GRAY ON RED PAUSE 2 RETURN ENDIF The command SHOW ERROR vhold displays the R:BASE message that corresponds to the error number. Some codes and corresponding messages are: Error number Message ------------ --------------------------------------------- 6 Database exists 7 Unable to Connect database 9 Illegal database name 42 Not enough space on this disk 93 No database connected 2059 No rows exist or satisfy the specified clause. To make your own message use WRITE commands or the technique described in "Making Application Menus & Message More R:BASE Like" from the May/ June 1991 Exchange (document #307 on automated FAX server 206-649-2789). The error variable is not always set after one of the DOS commands (DIR, TYPE, REN, DEL etc.) used in R:BASE. One way to check for the existence of a file is FILLIN filename_to_test USING 'Enter file name: ' LABEL retest OUTPUT temp_file TYPE filename_to_test SET VAR vhold = .verror OUTPUT SCREEN IF vhold = 0 THEN DIALOG 'File exists. Enter a new name, RETURN to overwrite.' + vresp,vkey,1 GOTO retest ENDIF The TYPE command sets the R:BASE error variable. Note that the error variable value is transferred to the holding variable immediately after the TYPE command and before the OUTPUT SCREEN. The OUTPUT SCREEN command resets the error variable to 0. If the file does not exist, the program continues with normal processing. If the file does not exist, you get an error code and can warn the user of the missing file. This does not work with all DOS commands. If the same syntax is used with a DIR filename command, for example, it does not return an error code. SQLCODE ======= Similar to the R:BASE ERROR VARIABLE is SQLCODE. SQLCODE is the ANSI SQL Level 2 defined error variable. It works like the R:BASE error variable in that it is set after every command, but it is only set after SQL commands, not after every R:BASE command as is the R:BASE error variable. Also, SQLCODE has specific defined values. It is 0 if the command is successful, 100 if no rows are found, and <0 if the command fails. When the command fails, SQLCODE is set to the negative of the R:BASE error code value. In R:BASE, SQLCODE is a system variable and does not to be defined. It is always there and is always being set, even if the value is not being checked by application code. SQLCODE is used just like the R:BASE error variable. After the command to be checked, the next line of code either tests SQLCODE or places the value of SQLCODE into a holding variable to be checked later. In addition, SQLCODE can be used with the WHENEVER command. For example: CONNECT concomp IF SQLCODE < 0 THEN CLS FROM 24,1 TO 24,80 RED WRITE 'Error connecting database.' AT 24,27 GRAY ON RED PAUSE 2 RETURN ENDIF WHENEVER ======== WHENEVER is like a gate; it checks SQLCODE and one continues through or goes around. This command is similar to the error variable in that it is placed once in the code and from there is used to check all subsequent commands. But while the R:BASE error variable is used once per R:BASE session, WHENEVER is used once per command file or block. Each command file or block requires a separate WHENEVER command, but they all share the same R:BASE error variable. There are two parts to the WHENEVER command: first, determine if an error condition exists; second, tell the program what to do. The first part of the WHENEVER clause includes two choices: SQLERROR which checks SQLCODE for all errors except "data not found" and NOT FOUND which checks only for a "data not found" error (SQLCODE=100). Since there can only be one WHENEVER per command file or block, it checks for data not found errors or for all other errors. This doesn't mean that you can't check SQLCODE directly in your code for data not found errors. It means that automatic processing of error handling code happens only for one or the other. If the first part of WHENEVER is true, then the second part of the WHENEVER command is executed. Like the first part, it has two options: GOTO label or CONTINUE. GOTO label passes program control to the specified label, usually an error handling routine that displays appropriate messages and determines the next step in the program. CONTINUE turns off a previously issued WHENEVER command within the same command file or block, the GOTO is not processed and the program continues with the next command line. One way to use the WHENEVER clause is to place the command, WHENEVER SQLERROR GOTO errorlab, at the beginning of each command file or block. If an error occurs at any line in the code, control is transferred to commands following the label, errorlab. It is not recommended to use WHENEVER NOT FOUND with DECLARE CURSOR to trap the end of data for the cursor. Often, cursors are used with UPDATE, INSERT and SELECT commands that have WHERE clauses. If the WHERE clause returns a "No rows exist or satisfy the specified clause", the WHENEVER NOT FOUND is triggered and the GOTO executed even though there may be more rows to be found with the cursor. Use WHILE SQLCODE <> 100 with DECLARE CURSOR. SQLERROR does not trap or process NOT FOUND errors, i.e. SQLCODE=100, it only deals with SQLCODE < 0. An example: WHENEVER SQLERROR GOTO errorlab CONNECT concomp ..... more code here LABEL errorlab SWITCH (SQLCODE) CASE '-7' CASE '-9' CLS FROM 24,1 TO 24,80 RED WRITE 'Error connecting database.' AT 24,27 GRAY ON RED PAUSE 2 RETURN BREAK CASE '-2045' CLS FROM 24,1 TO 24,80 RED WRITE 'Command did not execute due to synatx error.' + AT 24,18 GRAY ON RED PAUSE 2 GOTO start BREAK CASE 'DEFAULT CLS FROM 24,1 TO 24,80 RED WRITE 'An error has occurred. See your System Administrator.' + AT 24,12 GRAY ON RED PAUSE 2 RETURN BREAK ENDSW WHENEVER is only triggered by errors on SQL commands. It is not affected by non-SQL commands. Use the R:BASE error variable on non-SQL commands. This is not a comprehensive listing of what each error handling method can do, but a beginner's guide to error checking, how it affects your programs and some of the possible variations. If you are unsure as to how to use these in your program, consider the areas or commands that would cause the most pain and suffering. These areas would be considered excellent candidates for some error checking. If there are areas that are still unclear, the next best method of learning is trial and error. Note that these error handling routines process errors returned by R:BASE. They do not handle other errors such as: <> answering NO instead of YES <> wrong data values are returned <> wrong data values are entered <> ESC from menu or dialog box without making a selection These errors need to be tested for using custom program code.