Firebird Documentation IndexFirebird 2.5 SprachreferenzProzedurale SQL-Anweisungen (PSQL) → Abfangen und Behandeln von Fehlern
Firebird Home Firebird Home Zurück: Schreiben des Body-CodesFirebird Documentation IndexNach oben: Prozedurale SQL-Anweisungen (PSQL)Weiter: Eingebaute Funktionen und Variablen

Abfangen und Behandeln von Fehlern

Inhaltsverzeichnis

Systemausnahmen
Benutzerdefinierte Ausnahmen
EXCEPTION
WHEN ... DO

Firebird hat ein nützliches Lexikon von PSQL-Anweisungen und -Ressourcen, um Fehler in Modulen einzufangen und sie zu behandeln. Intern implementierte Ausnahmen existieren, um die Ausführung anzuhalten, wenn jeder Standardfehler in DDL, DSQL und der physischen Umgebung auftritt.

Systemausnahmen

Eine Ausnahme ist eine Nachricht, die generiert wird, wenn ein Fehler auftritt.

Alle Ausnahmen, die von Firebird behandelt werden, haben vordefinierte numerische Werte für Kontextvariablen (Symbole) und Textnachrichten, die ihnen zugeordnet sind. Fehlermeldungen werden standardmäßig in Englisch ausgegeben. Lokalisierte Firebird-Builds sind verfügbar, in denen Fehlermeldungen in andere Sprachen übersetzt werden.

Vollständige Auflistungen der Systemausnahmen finden Sie in Anhang B: Fehlercodes und Meldungen:

Benutzerdefinierte Ausnahmen

Benutzerdefinierte Ausnahmen können in der Datenbank als permanente Objekte deklariert und im PSQL-Code aufgerufen werden, um bestimmte Fehler zu signalisieren, zum Beispiel, um bestimmte Geschäftsregeln durchzusetzen. Eine benutzerdefinierte Ausnahme besteht aus einem Bezeichner und einer Standardnachricht von ungefähr 1000 Byte. Weitere Informationen finden Sie unter CREATE EXCEPTION.

Im PSQL-Code werden Ausnahmen mit der WHEN-Anweisung behandelt. Bei der Behandlung einer Ausnahme im Code wird entweder das Problem in situ behoben oder es wird übergangen. Bei beiden Lösungen kann die Ausführung fortgesetzt werden, ohne dass eine Ausnahmebedingungsnachricht an den Client zurückgegeben wird.

Eine Ausnahme führt dazu, dass die Ausführung im Block beendet wird. Anstatt die Ausführung an die END-Anweisung zu übergeben, bewegt sich die Prozedur durch Ebenen von verschachtelten Blöcken nach außen, beginnend mit dem Block, in dem die Ausnahme abgefangen wird, nach dem Code des Handlers, der diese Ausnahme „kennt“. Sie stoppt die Suche, wenn die erste WHEN-Anweisung gefunden wird, die diese Ausnahme verarbeiten kann.

EXCEPTION

Verwendet für:  Eine benutzerdefinierte Ausnahme auslösen oder eine Ausnahme erneut auslösen

Verfügbar in:  PSQL

Syntax: 

EXCEPTION [exception_name [custom_message]]
        

Tabelle 7.17. EXCEPTION-Statement-Parameter

Argument Beschreibung
exception_name Name der Ausnahme
custom_message Alternativer Nachrichtentext, der an die Aufruferschnittstelle zurückgegeben wird, wenn eine Ausnahme ausgelöst wird. Die maximale Länge der Textnachricht beträgt 1.021 Byte


Eine Anweisung EXCEPTION löst die benutzerdefinierte Ausnahme mit dem angegebenen Namen aus. Ein alternativer Nachrichtentext von bis zu 1.021 Byte kann optional den Standardnachrichtentext der Ausnahme überschreiben.

Die Ausnahmebedingung kann in der Anweisung behandelt werden, indem sie nur mit einem bestimmten WHEN ... DO-Handler belassen wird und dem Trigger oder der gespeicherten Prozedur erlaubt wird, alle Operationen zu beenden und rückgängig zu machen. Die aufrufende Anwendung erhält den alternativen Nachrichtentext, sofern einer angegeben wurde. Andernfalls empfängt es die ursprünglich für diese Ausnahme definierte Nachricht.

Innerhalb des Ausnahmebehandlungsblocks — und nur innerhalb davon — kann die abgefangene Ausnahme erneut ausgelöst werden, indem die Anweisung EXCEPTION ohne Parameter ausgeführt wird. Wenn der Befehl außerhalb des Blocks liegt, hat die erneut aufgerufene EXCEPTION-Anweisung keine Auswirkung.

Anmerkung

Benutzerdefinierte Ausnahmen werden in der Systemtabelle RDB$EXCEPTIONS gespeichert.

Beispiele: 

  1. Eine Ausnahme mit dynamisch erzeugtem Text auslösen:
    …
    EXCEPTION EX_BAD_TYPE
      'Incorrect record type with id ' || new.id;
    …
              
  2. Eine Ausnahme für eine Bedingung in der gespeicherten SHIP_ORDER-Prozedur auslösen:
    CREATE OR ALTER PROCEDURE SHIP_ORDER (
        PO_NUM CHAR(8))
    AS
    DECLARE VARIABLE ord_stat  CHAR(7);
    DECLARE VARIABLE hold_stat CHAR(1);
    DECLARE VARIABLE cust_no   INTEGER;
    DECLARE VARIABLE any_po    CHAR(8);
    BEGIN
      SELECT
          s.order_status,
          c.on_hold,
          c.cust_no
      FROM
          sales s, customer c
      WHERE
          po_number = :po_num AND
          s.cust_no = c.cust_no
      INTO :ord_stat,
           :hold_stat,
           :cust_no;
    
      IF (ord_stat = 'shipped') THEN
        EXCEPTION order_already_shipped;
      /* Other statements */
    END
                
  3. Eine Ausnahme bei einer Bedingung auslösen und die ursprüngliche Nachricht durch eine alternative Nachricht ersetzen:
    CREATE OR ALTER PROCEDURE SHIP_ORDER (
        PO_NUM CHAR(8))
    AS
    DECLARE VARIABLE ord_stat  CHAR(7);
    DECLARE VARIABLE hold_stat CHAR(1);
    DECLARE VARIABLE cust_no   INTEGER;
    DECLARE VARIABLE any_po    CHAR(8);
    BEGIN
      SELECT
          s.order_status,
          c.on_hold,
          c.cust_no
      FROM
          sales s, customer c
      WHERE
          po_number = :po_num AND
          s.cust_no = c.cust_no
      INTO :ord_stat,
           :hold_stat,
           :cust_no;
    
      IF (ord_stat = 'shipped') THEN
        EXCEPTION order_already_shipped
          'Order status is "' || ord_stat || '"';
      /* Other statements */
    END
                
  4. Einen Fehler protokollieren und erneut in den WHEN-Block werfen:
    CREATE PROCEDURE ADD_COUNTRY (
        ACountryName COUNTRYNAME,
        ACurrency VARCHAR(10) )
    AS
    BEGIN
      INSERT INTO country (country,
                           currency)
      VALUES (:ACountryName,
              :ACurrency);
      WHEN ANY DO
      BEGIN
            -- write an error in log
        IN AUTONOMOUS TRANSACTION DO
          INSERT INTO ERROR_LOG (PSQL_MODULE,
                                 GDS_CODE,
                                 SQL_CODE,
                                 SQL_STATE)
          VALUES ('ADD_COUNTRY',
                  GDSCODE,
                  SQLCODE,
                  SQLSTATE);
        -- Re-throw exception
        EXCEPTION;
      END
    END
                

Siehe auch:  CREATE EXCEPTION, WHEN ... DO

WHEN ... DO

Verwendet für:  Eine Ausnahme abfangen und den Fehler behandeln

Verfügbar in:  PSQL

Syntax: 

WHEN {<error> [, <error> …] | ANY}
DO <compound_statement>

<error> ::= {
    EXCEPTION exception_name
  | SQLCODE number
  | GDSCODE errcode
}
        

Tabelle 7.18. WHEN ... DO-Statement-Parameter

Argument Beschreibung
exception_name Name der Ausnahme
number SQLCODE Fehler-Code
errcode Symbolischer GDSCODE-Fehlername
compound_statement Ein Statement oder ein Block von Statements


Die Anweisung WHEN ... DO wird verwendet, um Fehler und benutzerdefinierte Ausnahmen zu behandeln. Die Anweisung erfasst alle Fehler und benutzerdefinierten Ausnahmen, die nach dem Schlüsselwort WHEN aufgeführt sind. Wenn WHEN das Schlüsselwort ANY folgt, fängt die Anweisung jeden Fehler oder jede benutzerdefinierte Ausnahme ab, auch wenn sie bereits in einer WHEN-Anweisung weiter oben im Block behandelt wurden.

Der WHEN ... DO-Block muss sich am Ende eines Anweisungsblocks befinden, vor der Anweisung END des Blocks.

Auf das Schlüsselwort DO folgt eine Anweisung oder ein Anweisungsblock innerhalb eines BEGIN ... END-Wrappers, der die Ausnahme behandelt. Die Kontextvariablen SQLCODE, GDSCODE und SQLSTATE stehen im Kontext dieser Anweisung oder dieses Blocks zur Verfügung. Die Anweisung EXCEPTION ohne Parameter kann auch in diesem Kontext verwendet werden, um den Fehler oder die Ausnahme erneut zu werfen.

Bezüglich GDSCODE

Das Argument für die Klausel WHEN GDSCODE ist der symbolische Name, der der intern definierten Ausnahme zugeordnet ist, z. B. grant_obj_notfound für den GDS-Fehler 335544551.

Nach der DO-Klausel wird eine weitere GDSCODE-Kontextvariable, die den numerischen Code enthält, für die Verwendung in der Anweisung oder dem Anweisungsblock verfügbar, die den Error-Handler codieren. Dieser numerische Code ist erforderlich, wenn Sie eine GDSCODE-Ausnahme mit einem gezielten Fehler vergleichen möchten.

Die WHEN ... DO-Anweisung oder der WHEN ... DO-Block werden niemals ausgeführt, es sei denn, eines der Ereignisse, auf die die Bedingungen abzielen, wird zur Laufzeit ausgeführt. Wenn die Anweisung ausgeführt wird, wird die Ausführung fortgesetzt, so als ob kein Fehler aufgetreten wäre: Der Fehler oder die benutzerdefinierte Ausnahme beendet weder die Operationen des Triggers noch der gespeicherten Prozedur.

Wenn jedoch die WHEN ... DO-Anweisung oder der WHEN ... DO-Block nichts zum Behandeln oder Beheben des Fehlers tut, wird die DML-Anweisung (SELECT, INSERT, UPDATE, DELETE, MERGE), die den Fehler verursacht hat zurückgerollt, und keine der Anweisungen darunter im selben Anweisungsblock wird ausgeführt.

Wichtig

  1. Wenn der Fehler nicht durch eine der DML-Anweisungen (SELECT, INSERT, UPDATE, DELETE, MERGE) verursacht wird, wird der gesamte Block der Anweisungen zurückgesetzt, nicht nur der, der einen Fehler verursacht hat. Alle Operationen in der WHEN ... DO-Anweisung werden ebenfalls zurückgesetzt. Dieselbe Einschränkung gilt für die Anweisung EXECUTE PROCEDURE. Lesen Sie eine interessante Diskussion über das Phänomen im Firebird Tracker-Ticket CORE-4483.
  2. Bei auswählbaren gespeicherten Prozeduren bleiben Ausgabezeilen, die bereits in früheren Iterationen einer FOR SELECT … DO … SUSPEND-Schleife an den Client übergeben wurden erhalten, wenn beim Abrufen von Zeilen eine Ausnahme ausgelöst wird.

Anwendungsbereiche einer WHEN ... DO Anweisung

Eine Anweisung WHEN ... DO fängt Fehler und Ausnahmen im aktuellen Anweisungsblock ab. Es fängt auch ähnliche Ausnahmen in verschachtelten Blöcken ab, wenn diese Ausnahmen nicht in ihnen behandelt wurden.

Alle Änderungen, die vor der Anweisung vorgenommen wurden, die den Fehler verursacht hat, sind für eine WHEN ... DO-Anweisung sichtbar. Wenn Sie jedoch versuchen, sie in einer autonomen Transaktion zu protokollieren, sind diese Änderungen nicht verfügbar, da die Transaktion, bei der die Änderungen stattfanden, zu dem Zeitpunkt, zu dem die autonome Transaktion gestartet wird, nicht festgeschrieben ist. Das untere Beispiel 4 zeigt dieses Verhalten.

Tipp

Bei der Behandlung von Ausnahmen ist es manchmal wünschenswert, die Ausnahme zu behandeln, indem eine Protokollnachricht geschrieben wird, um den Fehler zu markieren, und die Ausführung über den fehlerhaften Datensatz hinaus fortgesetzt wird. Protokolle können in reguläre Tabellen geschrieben werden, aber es gibt ein Problem damit: Die Protokolldatensätze „verschwinden“, wenn ein nicht behandelter Fehler dazu führt, dass das Modul nicht mehr ausgeführt wird und ein Rollback erfolgt. Die Verwendung von externen Tabellen kann hier nützlich sein, da Daten, die an sie geschrieben werden, transaktionsunabhängig sind. Die verknüpfte externe Datei ist immer noch vorhanden, unabhängig davon, ob der Gesamtprozess erfolgreich ist oder nicht.

Beispiele zur Verwendung von WHEN...DO: 

  1. Ersetzen des Standardfehlers durch einen benutzerdefinierten Fehler:
    CREATE EXCEPTION COUNTRY_EXIST '';
    SET TERM ^;
    CREATE PROCEDURE ADD_COUNTRY (
        ACountryName COUNTRYNAME,
        ACurrency VARCHAR(10) )
    AS
    BEGIN
      INSERT INTO country (country, currency)
      VALUES (:ACountryName, :ACurrency);
    
      WHEN SQLCODE -803 DO
        EXCEPTION COUNTRY_EXIST 'Country already exists!';
    END^
    SET TERM ^;
                  
  2. Einen Fehler protokollieren und erneut in den WHEN-Block werfen:
    CREATE PROCEDURE ADD_COUNTRY (
        ACountryName COUNTRYNAME,
        ACurrency VARCHAR(10) )
    AS
    BEGIN
      INSERT INTO country (country,
                           currency)
      VALUES (:ACountryName,
              :ACurrency);
      WHEN ANY DO
      BEGIN
        -- write an error in log
        IN AUTONOMOUS TRANSACTION DO
          INSERT INTO ERROR_LOG (PSQL_MODULE,
                                 GDS_CODE,
                                 SQL_CODE,
                                 SQL_STATE)
          VALUES ('ADD_COUNTRY',
                  GDSCODE,
                  SQLCODE,
                  SQLSTATE);
        -- Re-throw exception
        EXCEPTION;
      END
    END
                  
  3. Behandeln mehrerer Fehler in einem WHEN-Block
    ...
    WHEN GDSCODE GRANT_OBJ_NOTFOUND,
    	   GDSCODE GRANT_FLD_NOTFOUND,
    	   GDSCODE GRANT_NOPRIV,
    	   GDSCODE GRANT_NOPRIV_ON_BASE
    DO
    BEGIN
    	EXECUTE PROCEDURE LOG_GRANT_ERROR(GDSCODE);
    	EXIT;
    END
    ...
                  

Siehe auch:  EXCEPTION, CREATE EXCEPTION, SQLCODE und GDSCODE Fehlercodes und Meldungen (1) und SQLSTATE Fehlercodes und Meldungen

Zurück: Schreiben des Body-CodesFirebird Documentation IndexNach oben: Prozedurale SQL-Anweisungen (PSQL)Weiter: Eingebaute Funktionen und Variablen
Firebird Documentation IndexFirebird 2.5 SprachreferenzProzedurale SQL-Anweisungen (PSQL) → Abfangen und Behandeln von Fehlern