Fehler behandeln

Bei EGL können Sie entscheiden, wie sich das Programm bei Fehlern verhalten soll.

Fehlerbehandlung bedeutet, dass mögliche Arten von Problemen in einem Programm vorhergesehen werden und für jedes Problem ein Codepfad bereitgestellt wird. Falls Sie beschließen, Fehler nicht zu behandeln, bewirken praktisch selbst die trivialsten Fehler (siehe 'E/A-Fehler' weiter unten in diesem Abschnitt), dass Ihr Programm beendet wird.

Die Fehlerbehandlung in EGL geht vom Konzept der Ausnahmebedingung aus. Dies ist ein Stereotyp, der auf einen Datensatz angewendet wird. In EGL ist eine Reihe von Ausnahmebedingungen vordefiniert (siehe 'EGL-Ausnahmedatensätze' im Anhang der EGL-Sprachreferenz). Sie können aber auch eigene Ausnahmebedingungen definieren. Jeder Ausnahmedatensatz enthält mindestens die folgenden Felder:
messageID
Eine Zeichenfolge, die die EGL-Nachricht für die Ausnahmebedingung enthält. Wenn Sie beispielsweise versuchen, eine nicht initialisierte Feldgruppe zu verwenden, setzt EGL den Wert für messageID im Datensatz 'NullValueException' auf 'EGL0106E'.
message
Eine Zeichenfolge, die das Problem kurz erläutert. Die Nachricht mit dem Wert EGL0106E für messageID lautet beispielsweise 'Ein Nullverweis wurde verwendet'.

Der Ausnahmedatensatz kann gegebenenfalls weitere Felder enthalten. Beispielsweise enthält der Datensatz 'IndexOutOfBoundsException' ein zusätzliches Feld namens indexValue, das den Wert des Feldgruppenindexes enthält, der von EGL nicht verarbeitet werden konnte.

Try-Block

Das EGL-Schlüsselwort try leitet einen Codeblock ein, in dem Sie Ausnahmebedingungen abfangen und behandeln können. Falls innerhalb eines Try-Blocks eine Ausnahmebedingung auftritt, sucht EGL nach einer Anweisung onException im Try-Block, die mit dem Ausnahmebedingungstyp übereinstimmt. Jede Anweisung onException enthält die Deklaration einer Ausnahmebedingungsvariablen. Dieser Datensatz hat Ähnlichkeit mit den Variablen, die Sie an anderen Stellen in EGL deklarieren. Die Deklaration sieht etwa folgendermaßen aus:
onException(myEx NullValueException)
Dies bedeutet, dass Sie auf Felder in diesem Ausnahmedatensatz zugreifen können, falls EGL eine Ausnahmebedingung des Typs 'NullValueException' in diesem Try-Block auslöst. Beispielsweise können Sie die EGL-Nachrichten-ID in 'myEx.msgID' ermitteln, was im folgenden Beispiel dargestellt ist:
try
  intArray[10] = 0;  // this may not be initialized
onException(myEx NullValueException)
  writeStdErr(myEx);
  myErrorHandler(myEx);
end

Die Funktion myErrorHandler() könnte beispielsweise für die Initialisierung der Feldgruppe und die erneute Ausführung der Zuordnung zuständig sein.

Der besondere Ausnahmebedingungstyp AnyException dient dazu, jede beliebige Ausnahmebedingung abzufangen, und ist mit dem Basiselementtyp ANY vergleichbar. Sie deklarieren eine Datensatzvariable für AnyException. Falls EGL eine Ausnahmebedingung auslöst, nimmt die Variable den Typ des tatsächlichen Ausnahmedatensatzes an. Beispiel:
try
  get next mySerialRecord
onException(myEx AnyException)
  myErrorHandler(myEx);
end
Falls es einen bestimmten Codepfad gibt, der befolgt werden soll, wenn EGL eine Ausnahmebedingung des Typs 'FileIOException' auslöst, können Sie eine spezielle Überprüfung auf diesen Typ wie folgt hinzufügen:
try
  get next mySerialRecord
onException(myEx FileIOException)
   myErrorHandler1(myEx);
onException(myEx AnyException)
  myErrorHandler2(myEx);
end

Hier behandelt myErrorHandler2() alle Ausnahmebedingungen außer 'FileIOException'.

Falls EGL eine Ausnahmebedingung auslöst, die Ausnahmebedingung jedoch nicht von einem Block onException abgefangen wird, wird die Funktion sofort beendet und die Steuerung an die Funktion zurückgegeben, von der die Funktion, die den Fehler verursachte, aufgerufen wurde. Auf diese Weise übergibt EGL die Ausnahmebedingung an die übergeordneten Funktionen bis zu einer Funktion, die die Ausnahmebedingung mit einem Block onException abfängt, oder bis die Ausnahmebedingung die Hauptfunktion erreicht hat. Falls die Hauptfunktion die Ausnahmebedingung nicht abfangen kann, wird das Programm sofort beendet und das Nachrichtenfeld der Ausnahmebedingung wird in das Protokoll geschrieben. Wenn eine Ausnahmebedingung in einem über Fernzugriff aufgerufenen Programm auftritt, empfängt das aufrufende Programm statt der ursprünglichen Ausnahmebedingung eine Ausnahmebedingung des Typs 'InvocationException'. Analog liefert eine Ausnahmebedingung in einer Servicefunktion an das aufrufende Programm eine Ausnahmebedingung des Typs 'ServiceInvocationException'.

Anders ausgedrückt kann eine Funktion die Ausnahmebedingungen abfangen, die in den von ihr aufgerufenen Funktionen ausgelöst werden. Beispiel:
function FuncOne(myRec serialRecordType)
  try
    FuncTwo(myRec);
  onException(myEx AnyException)
    myErrorHandler2(myEx);
  end
end

function FuncTwo(myRec serialRecordType)
  get next myRec;
end
Im Kompatibilitätsmodus für Ausnahmebedingungen von Version 6 werden Ausnahmebedingungen nicht von Funktion zu Funktion übergeben. Dies ist nachfolgend erläutert.

Permanente und sporadisch auftretende E/A-Fehler

Wenn Sie Daten in einer Datei lesen oder schreiben, unterscheidet EGL zwischen permanenten und sporadisch auftretenden E/A-Fehlern. Die folgenden Fehler gelten als sporadisch, verursachen also wahrscheinlich keinen Datenverlust:

Tabelle 1. Sporadisch auftretende E/A-Fehler
Fehler Bedeutung
duplicate Bei einem indexierten oder relativen Datensatz gibt dieser Fehler an, dass ein zweiter Datensatz denselben Schlüssel besitzt.
endOfFile Bei einem seriellen, indexierten oder relativen Datensatz gibt dieser Fehler an, dass versucht wurde, über das Dateiende hinaus zu lesen.
noRecordFound Bei jedem Datensatztyp gibt dieser Fehler an, dass versucht wurde, einen Datensatz zu lesen, der nicht gefunden wurde.

Andere Fehler wie beispielsweise ein ungültiges Dateiformat oder eine volle Datei gelten als permanente Fehler. Ein permanenter E/A-Fehler für eine indexierte, relative oder serielle Datei löst 'FileIOException' aus. Ein permanenter E/A-Fehler für eine SQL-Datenbank löst 'SQLException' aus.

Sporadisch auftretende E/A-Fehler ordnen dem Datensatz einen Fehlerwert zu, führen jedoch nicht zum Auslösen einer Ausnahmebedingung. Zum Testen dieser Situation verwenden Sie den Operator is oder not. Sie müssen die betreffende E/A-Anweisung nicht in einen Try-Block einbetten, um diese Operatoren verwenden zu können. Falls Sie jedoch die E/A-Anweisung in einen Try-Block integrieren, können Sie gleichzeitig eine Prüfung auf permanente E/A-Fehler ausführen:
while(TRUE)  // endless loop
  try
    get next mySerialRecord;
    if(mySerialRecord is endOfFile)
      exit while;
    end
  onException(myEx AnyException)
    myErrorHandler(myEx);
  end
end

Eigenschaft 'throwNrfEofExceptions'

Die Programmeigenschaft throwNrfEofExceptions ist standardmäßig auf NO gesetzt. Dies bedeutet, dass das Programm nach den sporadisch auftretenden E/A-Fehlern noRecordFound und endOfFile selbst dann fortgesetzt wird, wenn der Fehler wie im folgenden Beispiel außerhalb eines Try-Blocks auftritt:
get myCustomer;
if(myCustomer is noRecordFound)
   add myCustomer;
end
Es kann jedoch sinnvoller sein, von EGL eine Ausnahmebedingung auslösen zu lassen, wenn einer dieser Fehler auftritt. Hierzu können Sie für die Programmeigenschaft throwNrfEofExceptions die Einstellung YES festlegen. In diesem Fall löst EGL eine der folgenden Ausnahmebedingungen aus:
  • Bei Ausführung einer Datei-E/A löst EGL 'RuntimeException' aus.
  • Bei Ausführung einer SQL-E/A löst EGL 'SQLException' aus.
Sie müssen diesen Fehler in einem Try-Block abfangen, da das Programm andernfalls beendet wird. Beim obigen Beispiel wird das Programm beendet, falls für die Anweisung get kein Datensatz gefunden wird. Mit einem der folgenden Verfahren können Sie die Ausnahmebedingung jedoch behandeln:
  • Nach dem sporadisch auftretenden Fehler fortsetzen:
    try
      get myCustomer; 
    end
    
    if (myCustomer is noRecordFound) 
      add myCustomer; 
    end
  • Ausnahmebedingung abfangen (empfohlenes Verfahren):
    try
      get myCustomer; 
    onException (myEx FileIOException)
      if (myCustomer is noRecordFound) 
        add myCustomer; 
      else
        myErrorHandler(myEx);
      end
    end

Eigene Ausnahmebedingungen auslösen

Mit einer EGL-Anweisung throw können Sie jede beliebige der vordefinierten Systemausnahmebedingungen auslösen. Wie bei der Ausnahmebedingungsbehandlung müssen Sie eine Variable basierend auf dem Datensatz deklarieren:
nullEx NullValueException{};
 ... 
throw nullEx;
Zusätzlich zu den vom System definierten Ausnahmebedingungen können Sie eigene Ausnahmedatensätze erstellen. Wie bei anderen Datensätzen müssen Sie zunächst einen Datensatzabschnitt definieren und dann auf seiner Grundlage eine Variable deklarieren.
Record CustomerException type Exception
  customerNumber INT;
end
 ... 
throw new customerException {
  customerNumber = custNum,
  message = "Illegal customer number" };
Angepasste Ausnahmedatensätze wie dieser enthalten wie die Datensätze für Systemausnahmebedingungen automatisch die Felder messageID und message .

Kompatibilität für Ausnahmebedingungen in Version 6

Zur Kompatibilität mit früheren Versionen können Sie weiterhin die Fehlerbehandlungsverfahren aus Version 6 von EGL verwenden.

Sie geben den V6-Ausnahmemodus für jedes Programm separat an, wenn Sie die Eigenschaft v60ExceptionCompatibility des Programms auf YES setzen. Die besten Ergebnisse erzielen Sie jedoch, wenn Sie für alle Ihre Programme dieselbe Einstellung verwenden.

V6-Ausnahmebedingungen werden normalerweise durch einen Try-Block behandelt. Der Unterschied besteht darin, dass V6-Ausnahmebedingungen nur eine einzige Anweisung onException zulassen und keinen Ausnahmebedingungstyp angeben. Auf diese Weise wird dasselbe Verhalten erreicht wie bei einer Anweisung onException mit einem impliziten Änderungswert 'AnyException':
try
  posNum = abs(myVar);
onException
  if(sysVar.errorCode = "00000008") // invalid input
    myErrorHandler1();
  if(sysVar.errorCode = "00000012") // cannot assign value
    myErrorHandler2();
  else
    myErrorHandler3();
end
Die Kompatibilität für V6-Ausnahmebedingungen basiert nicht auf Ausnahmedatensätzen, sondern stützt sich auf die Systemvariable sysVar.errorCode. Bei Ausführung im V6-Ausnahmemodus wird sysVar.errorCode in den folgenden Fällen festgelegt:
  • Beim Abschluss einer Anweisung call
  • Nach dem Aufruf eines Service
  • Nach einer E/A-Anweisung für eine Datei (z. B. get oder replace)
  • Nach dem Aufruf vieler EGL-Systemfunktionen
Für SQL-E/A-Fehler stützt sich die Kompatibilität für V6-Ausnahmebedingungen außerdem auf die Systemvariablen in sysVar.sqlData.
Sie benötigen keinen Try-Block, um im V6-Ausnahmemodus auf sysVar.errorCode zuzugreifen, falls für die Systemvariable vgVar.handleSysLibraryErrors (für Funktionen in Systembibliotheken) oder vgVar.handleHardIOErrors (für Datei- und SQL-E/A) die Einstellung 1 festgelegt ist:
vgVar.handleSysLibraryErrors = 1;
posNum = abs(myVar);
if(sysVar.errorCode == "00000008") // invalid input
  myErrorHandler1();
else
  if(sysVar.errorCode == "00000012") // cannot assign
    myErrorHandler2();
  else
    exit program (-1);
  end
end

Wenn für vgVar.handleSysLibraryErrors jedoch 0 (Standardeinstellung) festgelegt ist und Sie keinen Try-Block zum Abfangen von Ausnahmebedingungen verwenden, führt jede Ausnahmebedingung zur Beendigung des Programms.

Weitere Informationen hierzu finden Sie in Ausnahmebedingungsbehandlung.


Feedback