|Powered by QM on a Rpi server|
KnowledgeBase 00092: Use of the ON ERROR Clause
This article was originally published as a Tip of the Week.
Many QMBasic file handling statements have an optional ON ERROR clause that can be used to capture certain error conditions that would otherwise cause the program to abort. Most applications, however, should not need to use this clause as the default action of QM is usually appropriate and sufficiently informative.
QMBasic file handling statements tend to have various combinations of four optional error detection clauses; ON ERROR, LOCKED, THEN and ELSE. When more than one clause is present, they must be in this order. The LOCKED clause allows a program to detect that it would otherwise be blocked waiting for a lock and is not discussed further here.
The THEN and ELSE clauses are found in many QMBasic statements, not just those concerned with file handling. The THEN clause is executed if the action of the statement is successful and the ELSE clause is executed if the action fails in some simple way such as trying to read a record that does not exist. In many cases such errors are valid situations in a program.
More serious errors such as detection of corruption to the internal structure of a hashed file normally cause QM to abort the process with a descriptive error message displayed to the user and written to the error log (if it is enabled). Note that these are all complex error conditions that should never occur, even as a result of errors on the part of the user or developer.
The ON ERROR clause allows a program to trap internal errors that would otherwise cause an abort. It is highly unlikely that most applications could perform any useful recovery action from such an error and hence the ON ERROR clause should be very rarely needed.
One possible use for this clause might be in a web server program where failure should display an error page on the browser. Even here, it is probably better to implement this from the ON.ABORT VOC item rather than adding ON ERROR clauses to every file operation in the application.
An ON ERROR clause that does nothing more than abort the program serves no purpose and excessive use of such clauses is likely to make a program difficult to read.
Exceptions to the Rule
There are two situations where ON ERROR clauses possibly have valid use. Both of these are concerned with the WRITE and DELETE statements (and variants such as WRITEV, MATWRITE or DELETEU).
Historically, with the exception of UniVerse, the Basic language used by multivalue systems has not included a THEN/ELSE clause in WRITE or DELETE statements. Therefore, without changing the syntax in a potentially incompatible manner (see below), there is no way in which to return errors such as running out of disk space when writing a record.
Without an ON ERROR clause a WRITE would abort if there is insufficient space to complete its operation. Use of ON ERROR allows this to be trapped. Although this is a very unlikely situation on modern systems, it can happen and it may be considered appropriate to code for it. Some parts of QM such as the ED and SED editors do this so that the user can make space and try saving the data again. Note that it is possible (though very unlikely) to run out of disk space when deleting a record in a hashed file.
The second exception is when using pre-write or pre-delete triggers to perform data integrity checks. Although the trigger function can detect whether the operation being performed has an ON ERORR clause and take alternative actions, the default behaviour is that a disallowed write or delete will cause the ON ERROR clause to be executed, if present, aborting the program if there is no such clause.
Why No THEN/ELSE?
It might seem reasonable for WRITE and DELETE to have an optional THEN/ELSE clause. Changing the syntax of these statements would, however, lead to an incompatibility that may alter the behaviour of existing programs.
Consider a simple program that maintains a record per-customer listing the invoices open to that customer. Closing the final invoice would delete the record. QMBasic statements to handle the update when an invoice has been removed from the list might be
IF INVOICES # '' THEN WRITE INVOICES TO CUSTINV.F, CUST.NO ELSE DELETE CUSTINV.F, CUST.NOWith the current syntax the ELSE pairs with the IF on the previous line such that the record is written if not empty but deleted if empty. Changing the syntax of WRITE to have an optional THEN/ELSE would result in the ELSE pairing with the WRITE, leaving the old record in place when it should have been deleted. Making THEN/ELSE mandatory on a WRITE would require big changes to all applications.