Your Browser is not longer supported

Please use Google Chrome, Mozilla Firefox or Microsoft Edge to view the page correctly
Loading...

{{viewport.spaceProperty.prod}}

Diagnoseinformationen in Routinen

SESAM/SQL stellt Diagnoseinformationen in Routinen bereit. Die SQL-Norm verwendet dafür den Begriff „Diagnostics Management“.

Diagnoseinformationen werden für eine zuvor ausgeführte SQL-Anweisung in einem Diagnosebereich bereitgestellt. Bei Routinen in SESAM/SQL kann es zu einem Zeitpunkt mehrere Diagnosebereiche geben (für eine SQL-Anweisung, bei Aufruf einer (Fehler-)Routine), speziell bei geschachtelten Routinen.

An der ESQL-Cobol-Schnittstelle, also im Anwenderprogramm, hat der Diagnosebereich den Namen „SQLda“.

Mit folgenden SQL-Anweisungen, die nur in Routinen verwendet werden dürfen, kann lesend und/oder schreibend auf einen Diagnosebereich zugegriffen werden:

SQL-Anweisung

Funktion

siehe

GET DIAGNOSTICS

Diagnoseinformationen zu einer Anweisung ausgeben

"GET DIAGNOSTICS - Diagnoseinformationen ausgeben"

SIGNAL

Fehler in Routine melden

"SIGNAL - Fehler in Routine melden"

RESIGNAL

Fehler in lokaler Fehler-Routine melden

"RESIGNAL - Fehler in lokaler Fehler-Routine melden"

Tabelle 29: Kontroll- und Diagnoseanweisungen von Routinen

Durch diese Diagnoseanweisungen und die nachfolgend beschriebenen selbst definierten SQLSTATEs können Sie die Programmierung von Routinen verbessern. Sie können auftretende Fehler genauer analysieren und differenziert darauf reagieren.

Erfolg einer SQL-Anweisung in einer Routine

Der Erfolg einer SQL-Anweisung in einer Routine wird zur einfacheren Beschreibung in diesem Handbuch so definiert:

  • Die SQL-Anweisung war erfolgreich, wenn sie mit SQLSTATE '00000' beendet wurde.

  • Die SQL-Anweisung war fehlerfrei, wenn sie mit SQLSTATE '00000', einem SQLSTATE der Klassen '01xxx' (Warnung) oder '02xxx' (keine Daten) beendet wurde.

  • Die SQL-Anweisung in einer Routine war fehlerhaft, wenn sie nicht fehlerfrei beendet wurde.

Eine Routine wird nach einer fehlerfreien SQL-Anweisung fortgesetzt, wenn keine Fehler-Routinen für die SQLSTATEs der Klassen '01000' und '02000' definiert sind. Wenn z.B. bei einer SQL-Anweisung in einer Prozedur eine Warnung auftritt, dann wird die entsprechende CALL-Anweisung mit SQLSTATE '00000' beendet.

Selbst definierte SQLSTATEs

Mit SESAM/SQL ab V9.0 können Sie SQLSTATEs selbst definieren. Für sie ist die Klasse '46Sxx' (x ist eine Zahl oder ein Großbuchstabe) reserviert. In dieser Klasse können Sie so bis zu 1296 SQLSTATEs selbst definieren. Diese Klasse wird weder von der SQL-Norm noch von SESAM/SQL verwendet.

Selbst definierte SQLSTATEs können Sie in den Diagnoseanweisungen SIGNAL und RESIGNAL angeben.Mit einem selbst definierten SQLSTATE können Sie in der Diagnoseanweisung SIGNAL gezielt eine bestimmte Fehler-Routine aufrufen. In der Fehler-Routine können Sie mit der Diagnoseanweisung RESIGNAL die Routine gezielt abbrechen. In beide Anweisungen können Sie auch zusätzliche Diagnoseinformationen in den Diagnosebereich eintragen.

Für selbst definierte SQLSTATEs gibt es keine vorgefertigten SESAM-Meldungstexte. Wenn ein selbst definierter SQLSTATE als unbehandelter SQLSTATE in das Anwendungsprogramm gelangt, dann generiert SESAM/SQL daraus die Meldung SEW46xx (&00). Als Insert (&00) erscheint dann der MESSAGE_TEXT aus dem Diagnosebereich. Sie können damit in den Diagnoseanweisungen SIGNAL und RESIGNAL indirekt einen eigenen Meldungstext (ohne begleitenden Hilfetext) erzeugen.

SQLSTATE '45000' (unbehandelter SQLSTATE)

Mit SESAM/SQL können Sie in einer COMPOUND-Anweisung einen lokalen Fehlernamen für einen SQLSTATE definieren, siehe Abschnitt „Lokale Daten".

Sie können aber auch einen Fehlernamen ohne Verknüpfung mit einem SQLSTATE definieren.

Mit diesem Fehlernamen können Sie in der Diagnoseanweisung SIGNAL eine bestimmte Fehler-Routine aufrufen. Wenn diese Fehler-Routine nicht existiert oder mit RESIGNAL (ohne Angabe eines SQLSTATE) verlassen wird, dann dann wird die Routine mit dem SQLSTATE '45000' beendet.

SESAM/SQL erzeugt daraus folgende Meldung:

SEW4500 UNHANDLED USER DEFINED EXCEPTION (&00). (&01)

Das Insert (&00) enthält den Fehlernamen. Wenn bei SIGNAL bzw. RESIGNAL ein MESSAGE_TEXT angegeben wurde, dann erscheint er als Insert (&01).

Bei geeigneter Wahl des Fehlernamens und ggf. eines entsprechenden MESSAGE_TEXT erhält der Anwender somit eine aussagekräftige Meldung.

GET DIAGNOSTICS

GET DIAGNOSTICS ermittelt Informationen zu einer zuvor in einer Routine ausgeführten SQL-Anweisung und trägt diese in einen Prozedurparameter (Ausgabe) oder eine lokale Variable ein. Die Informationen beziehen sich auf die Anweisung selbst oder auf die davon betroffenen Objekte der Datenbank.

GET DIAGNOSTICS ändert weder Inhalt noch Reihenfolge von Diagnosebereichen. D.h. unmittelbar aufeinander folgende GET DIAGNOSTICS-Anweisungen werten dieselbe Diagnoseinformation aus.

Die detaillierte Beschreibung der GET DIAGNOSTICS-Anweisung finden Sie auf "GET DIAGNOSTICS - Diagnoseinformationen ausgeben".

SIGNAL

SIGNAL meldet in einer Routine einen Fehler oder einen selbst definierten SQLSTATE.

Die detaillierte Beschreibung der SIGNAL-Anweisung finden Sie auf "SIGNAL - Fehler in Routine melden".

SIGNAL löscht den aktuellen Diagnosebereich und trägt optional folgende Diagnoseinformationen in den aktuellen Diagnosebereich ein:

  • Bei Angabe eines Fehlernamens wird dieser als CONDITION_IDENTIFIER eingetragen. Sonst wird eine Zeichenkette der Länge 0 zugewiesen.

  • Der RETURNED_SQLSTATE wird versorgt:

    • Bei Angabe eines SQLSTATE wird dieser als RETURNED_SQLSTATE eingetragenn

    • Wenn für den angegebenen Fehlernamen ein SQLSTATE definiert ist, dann wird für RETURNED_SQLSTATE der definierte SQLSTATE eingetragen

    • Sonst wird der SQLSTATE '45000' eingetragen

  • Bei Angabe von MESSAGE_TEXT werden MESSAGE_TEXT, MESSAGE_LENGTH und MESSAGE_OCTET_LENGTH entsprechend versorgt. Sonst wird MESSAGE_TEXT eine Zeichenkette der Länge 0 zugewiesen.

Die Routine wird mit einer Fehler-Routine fortgesetzt oder beendet:

  • Wenn RETURNED_SQLSTATE ≠ '45000' und für den RETURNED_SQLSTATE eine lokale Fehler-Routine definiert ist, dann wird diese Fehler-Routine ausgeführt.

  • Wenn RETURNED_SQLSTATE = '45000' und für den in CONDITION_IDENTIFIER eingetragenen Fehlernamen eine lokale Fehler-Routine definiert ist, dann wird diese Fehler-Routine ausgeführt.

  • Sonst liegt ein unbehandelter SQLSTATE vor. Die Routine wird mit dem in RETURNE-D_SQLSTATE eingetragenen SQLSTATE beendet.

Weitere Hinweise:

  • Mit SIGNAL kann die Ausführung einer bestimmten Fehler-Routine erreicht werden.

  • Eine unmittelbar hinter der SIGNAL-Anweisung stehende SQL-Anweisung wird nur dann durchlaufen, wenn die durch SIGNAL aufgerufene Fehler-Routine mit CONTINUE definiert ist und fehlerfrei beendet wurde.

  • Wenn die bei SIGNAL in den Diagnosebereich eingetragenen Werte (wie z.B. MESSAGE_TEXT) gelesen werden sollen, dann muss GET CURRENT DIAGNOSTICS entweder unmittelbar nach SIGNAL stehen (siehe vorherigen Hinweis) oder es muss in der aufgerufenen Fehler-Routine GET STACKED DIAGNOSTICS verwendet werden. Diese Fehler-Routine muss nicht notwendigerweise Teil der aktuellen COMPOUND-Anweisung sein. Sie kann auch eine Fehler-Routine einer übergeordneten Routine sein, die die Routine mit der SIGNAL-Anweisung verwendet hat. Im letzteren Fall wird dann also der Diagnosebereich der aufrufenden Anweisung ausgewertet.

  • Eine Routine wird nach einer fehlerfreien,aber nicht erfolgreichen SQL-Anweisung fortgesetzt. Selbst wenn in einem solchen Fall eine Fehler-Routine mit EXIT oder UNDO durchlaufen wurde, beendet sich die Routine mit SQLSTATE '00000', es sei denn in der Fehler-Routine selbst wurde eine SQL-Anweisung fehlerhaft beendet. Mit der SIGNAL-Anweisung kann in einem derartigen Fall die Routine mit einem selbst definierten SQLSTATE beendet werden.

RESIGNAL

RESIGNAL meldet in einer lokalen Fehler-Routine eine Bedingung oder einen SQLSTATE. Im Unterschied zu SIGNAL ist die Angabe eines Fehlernamens oder eines SQLSTATE optional.

Die detaillierte Beschreibung der RESIGNAL-Anweisung finden Sie auf "RESIGNAL - Fehler in lokaler Fehler-Routine melden".

RESIGNAL verwendet den Diagnosebereich der SQL-Anweisung, die die Fehler-Routine aktiviert hat, als aktuellen Diagnosebereich und ändert ggf. folgende Diagnoseinformationen::

  • Wenn weder Fehlername noch SQLSTATE angegeben werden, dann bleiben CONDITION_IDENTIFIER und RETURNED_SQLSTATE unverändert. Es gilt:

    • RETURNED_SQLSTATE darf keinen SQLSTATE der Klassen '01xxx' oder '02xxx' enthalten. Sonst wird RESIGNAL mit Fehler beendet.

    • Wenn MESSAGE_TEXT= angegeben ist, dann muss RETURNED_SQLSTATE entweder einen selbst definierten SQLSTATE oder den Wert '45000' enthalten. Sonst wird RESIGNAL mit Fehler beendet.

  • Der aktuelle Diagnosebereich wird ggf. modifiziert:

    • Bei Angabe eines Fehlernamens wird dieser als CONDITION_IDENTIFIER eingetragen. Sonst wird eine Zeichenkette der Länge 0 zugewiesen.

    • Bei Angabe eines SQLSTATE wird dieser als RETURNED_SQLSTATE eingetragen..

    • Wenn für den angegebenen Fehlernamen ein SQLSTATE definiert ist, dann wird für RETURNED_SQLSTATE der definierte SQLSTATE eingetragen. Sonst wird der SQLSTATE '45000' eingetragen.

  • Bei Angabe von MESSAGE_TEXT werden MESSAGE_TEXT, MESSAGE_LENGTH und MESSAGE_OCTET_LENGTH entsprechend versorgt. Sonst wird MESSAGE_TEXT eine Zeichenkette der Länge 0 zugewiesen.

Die Routine, in der die lokale Fehler-Routine mit der RESIGNAL-Anweisung durchlaufen wurde, wird mit dem in RETURNED_SQLSTATE eingetragenen SQLSTATE beendet.

Weitere Hinweise:

  • Eine Routine wird auch nach Durchlaufen einer Fehler-Routine, die mit EXIT oder UNDO definiert ist, mit SQLSTATE '00000' beendet, es sei denn in der Fehler-Routine selbst wurde eine SQL-Anweisung fehlerhaft beendet. Mit RESIGNAL können Sie den SQLSTATE, der die Fehler-Routine ausgelöst hat, zurückmelden.

  • Eine SIGNAL-Anweisung, die in einer Fehler-Routine aufgerufen wird, hat den gleichen Effekt wie eine RESIGNAL-Anweisung mit explizit angegebenem Fehlernamen oder SQLSTATE.

Beispiele für den Einsatz der Diagnoseanweisungen

Unterschiedliche Situationen bei der Abfrage des SQLSTATEs

CREATE PROCEDURE proc1() MODIFIES SQL DATA
   BEGIN ATOMIC
      DECLARE state1, state2, state3 CHAR(5);
      DECLARE EXIT HANDLER FOR SQLEXCEPTION
         BEGIN
            DELETE FROM tab1; ------------------------------------------- (3)
            GET STACKED DIAGNOSTICS CONDITION state2 = RETURNED_SQLSTATE;
            GET CURRENT DIAGNOSTICS CONDITION state3 = RETURNED_SQLSTATE;
            ... --------------------------------------------------------- (2)
         END;
      ...
      UPDATE tab2 SET ...;
      GET CURRENT DIAGNOSTICS CONDITION state1 = RETURNED_SQLSTATE; ----- (1)
      ...
   END

(1)

Die lokale Variable state1 wird nur dann versorgt, wenn die UPDATE-Anweisung erfolgreich oder fehlerfrei durchlaufen wurde. Sie enthält dann entweder den SQLSTATE '00000', eine Warnung oder den SQLSTATE '02000' (keine Daten). Die Fehler-Routine wird nicht durchlaufen.

(2)

Wenn die UPDATE-Anweisung mit Fehler und die DELETE-Anweisung ohne Fehler durchlaufen wurde, dann enthält state2 den SQLSTATE der UPDATE-Anweisung, die den Fehler verursacht hat.
state3 enthält den SQLSTATE der DELETE-Anweisung ('00000', eine Warnung oder '02000' (keine Daten)).
state1 wird nicht versorgt, da die Prozedur wegen der Fehler-Routine (EXIT) abgebrochen wurde.

(3)

Wenn auch die DELETE-Anweisung der Fehler-Routine mit Fehler durchlaufen wurde, dann wird die Prozedur wegen des unbehandelten SQLSTATEs sofort abgebrochen. Es wird keine der GET DIAGNOSTICS-Anweisungen durchlaufen.

Wenn die Fehler-Routine (statt mit EXIT) mit CONTINUE definiert ist und ohne Fehler durchlaufen wird, dann wird state1 auch nach einer UPDATE-Anweisung, die mit Fehler durchlaufen wurde, versorgt. state1 erhält dann den SQLSTATE der UPDATE-Anweisung, die den Fehler verursacht hat.


Spezielle Behandlung des SQLSTATE '02000'

Nach SQLSTATE '02000' (keine Daten) wird eine Routine normalerweise fortgesetzt. Im folgenden Beispiel wird das in einem Fall akzeptiert, in einem anderen Fall soll es zu einem Fehler führen.

CREATE PROCEDURE proc2(OUT par1 INTEGER, OUT par2 INTEGER) MODIFIES SQL DATA
   BEGIN ATOMIC
      DELETE FROM tab1;
      GET DIAGNOSTICS par1 = ROW_COUNT;
      DELETE FROM tab2;
      GET DIAGNOSTICS par2 = ROW_COUNT;
      IF par2 = 0 
         THEN SIGNAL SQLSTATE '46SA1'
              SET MESSAGE_TEXT = 'tab2 must contain at least one record';
      END IF;
   END

Wenn die DELETE-Anweisungen ohne Fehler durchlaufen wurden, dann wird die jeweilige Anzahl der gelöschten Sätze in den beiden Ausgabeparametern eingetragen. Bei Tabelle tab1 darf die Anzahl auch 0 sein. Wenn aber Tabelle tab2 leer ist, dann wird die Prozedur abgebrochen. Wegen der Klausel ATOMIC werden auch die Löschungen in der Tabelle tab1 rückgängig gemacht. SESAM/SQL generiert die Meldung:

SEW46A1 TAB2 MUST CONTAIN AT LEAST ONE RECORD


Merken des aufgetretenen SQLSTATE

Nach einem unbehandelten SQLSTATE wird eine Prozedur abgebrochen und genau dieser SQLSTATE gemeldet. Wenn Sie dieses Ereignis zusätzlich in einer Tabelle protokollieren möchten, dann definieren Sie z.B. nachfolgende Fehler-Routine. Mit der RESIGNAL-Anweisung wird der aufgetretene SQLSTATE zurückgemeldet. Ohne die RESIGNAL-Anweisung würde sich die Prozedur mit SQLSTATE '00000' beenden.

CREATE PROCEDURE proc3() MODIFIES SQL DATA
   BEGIN ATOMIC
      DECLARE error CHAR(5);
      DECLARE UNDO HANDLER FOR SQLEXCEPTION
      BEGIN
         GET DIAGNOSTICS CONDITION error = RETURNED_SQLSTATE;
         INSERT INTO logging_tab 
           VALUES (CURRENT_TIMESTAMP(3),'SQLSTATE ' || error || ' occurred');
         RESIGNAL;
      END;
   -- procedure body
   ...
   END


Suche nach leeren Tabellen

Die Anzahl leerer Tabellen soll über eine User Defined Function ermittelt werden. Wenn die Anzahl leerer Tabellen die eingegebene Anzahl übersteigt, dann soll die Suche mit Fehler abgebrochen werden.

CREATE FUNCTION check_tables(IN max_nbr INTEGER) 
                RETURNS INTEGER READS SQL DATA
   BEGIN
      DECLARE "TABLE ERROR" CONDITION;
      DECLARE nbr_empty_tables integer DEFAULT 0;
      DECLARE CONTINUE HANDLER FOR "TABLE ERROR"
         BEGIN
            nbr_empty_tables = nbr_empty_tables + 1;
            IF nbr_empty_tables > max_nbr 
               THEN RESIGNAL SET MESSAGE_TEXT = 'TOO MANY EMPTY TABLES';
            END IF;
         END;
   IF (SELECT COUNT(*) FROM tab1) = 0 THEN SIGNAL "TABLE ERROR";
   END IF;
   IF (SELECT COUNT(*) FROM tab2) = 0 THEN SIGNAL "TABLE ERROR";
   END IF;
   IF (SELECT COUNT(*) FROM tab3) = 0 THEN SIGNAL "TABLE ERROR";
   END IF;
   RETURN nbr_empty_tables;
   END
SELECT check_tables(2) INTO :NBR-EMPTY-TABLES FROM TABLE(DEE)

Wenn die Anzahl leerer Tabellen die eingegebene Anzahl nicht übersteigt, dann wird die Anzahl leerer Tabellen in der Benutzervariablen :NBR-EMPTY-TABLES abgelegt.

Wenn aber mehr als zwei leere Tabellen existieren, wird die Suche mit SQLSTATE '45000' beendet. SESAM/SQL generiert dann folgende Meldung:

SEW4500 UNHANDLED USER DEFINED EXCEPTION (TABLE ERROR). TOO MANY EMPTY TABLES