Mit der DECLARE HANDLER-Anweisung wird ein Fehlerbehandlungsprogramm für die Handhabung von Ausnahmen erstellt.
>>-DECLARE--+-CONTINUE-+--HANDLER FOR--| State |--Anweisung---->< '-EXIT-----' State .-<<-- , --<<------------------------------------------------. V | |------SQLSTATE--+-+-------+--' Text '----------------------+---+--| | '-VALUE-' | '---LIKE--' Text '--+------------------+---' '-ESCAPE--' Text '-'
Sie können Steuerroutinen sowohl in explizit deklarierten Bereichen (BEGIN...END) erstellen als auch in implizit deklarierten Bereichen (wie beispielsweise durch die ELSE-Klausel einer IF-Anweisung). Alle Deklarationen für Steuerroutinen müssen jedoch am Beginn eines Bereichs, vor allen anderen Anweisungen, stehen.
Tritt keine Ausnahme auf, hat die Steuerroutine keine Auswirkungen auf das Verhalten oder die Leistung eines SQL-Programms. Tritt eine Ausnahme auf, vergleicht WebSphere Message Broker den SQL-Status der Ausnahme mit dem der relevanten Steuerroutinen, bis die Ausnahme entweder den Knoten wieder verlässt (wie dies auch der Fall wäre, wenn keine Steuerroutinen vorhanden wären) oder bis die entsprechende Steuerroutine gefunden wird. In jedem einzelnen Bereich wird nach Steuerroutinen in der Reihenfolge gesucht, in der sie erstellt wurden, d. h. von der zuerst bis zu der zuletzt erstellten Steuerroutine. Die Bereiche werden vom innersten hin zum äußersten durchsucht.
Die in den DECLARE... HANDLER...-Anweisungen zur Verfügung gestellten SQL-Statuswerte können direkt mit dem SQL-Status einer Ausnahme verglichen werden oder mithilfe von Platzhalterzeichen. Damit Statuswerte direkt verglichen werden können, müssen Sie entweder VALUE oder einen Operator, für den keine Bedingungen erfüllt werden müssen, angeben. Für einen Vergleich mithilfe von Platzhalterzeichen werden das Unterstreichungszeichen und das Prozentzeichen (mit deren Hilfe einzelne bzw. mehrere Zeichen abgedeckt werden) sowie der LIKE-Operator angegeben. Bei der Verwendung von Platzhalterzeichen können alle Ausnahmen eines allgemeinen Typs behandelt werden, ohne dass die Ausnahmen alle einzeln aufgeführt werden müssen.
Wird eine entsprechende Steuerroutine gefunden, werden das Register SQLSTATE sowie andere Sonderregister (gemäß den später in diesem Abschnitt beschriebenen Regeln) aktualisiert und die Anweisung der Steuerroutine wird verarbeitet.
Da die Anweisung der Steuerroutine eine einzige Anweisung sein muss, handelt es sich in der Regel um eine zusammengesetzte Anweisung (wie beispielsweise BEGIN...END), die mehrere andere Anweisungen enthält. Es ist kein besonderes Verhalten in Zusammenhang mit diesen internen Anweisungen vorgegeben und es bestehen auch keine Einschränkungen. Zu diesen internen Anweisungen gehören beispielsweise RETURN, ITERATE oder LEAVE; sie wirken sich auf die in ihnen enthaltenen Routinen und Schleifenkonstrukte genauso aus, als ob diese im Bereich selbst enthalten wären.
Steuerroutinen können wiederum Steuerroutinen für Ausnahmen enthalten, die in diesen übergeordneten Steuerroutinen selbst auftreten.
Jede Steuerroutine verfügt über ihre eigenen Sonderregister SQLCODE, SQLSTATE, SQLNATIVEERROR und SQLERRORTEXT. Unmittelbar vor der Ausführung der ersten Anweisung der Steuerroutine treten sie in den Bereich ein und ihre Werte werden gesetzt. Sie bleiben gültig, bis die letzte Anweisung der Steuerroutine ausgeführt wurde. Da SQLSTATE-Werte nicht von einer Steuerroutine in eine andere übernommen werden, können Steuerroutinen unabhängig voneinander erstellt werden.
Steuerroutinen übernehmen Ausnahmen und verhindern, dass sie den Empfangsknoten erreichen; dadurch wird die Transaktion nicht zurückgesetzt, sondern festgeschrieben. Eine Steuerroutine kann dies durch Verwendung einer RESIGNAL- oder THROW-Anwendung verhindern.
Der Abschnitt SQLSTATE-Funktion enthält eine Liste der gültigen SQLSTATE-Werte, die in einer HANDLER-Anweisung verwendet werden können.
DECLARE retryCount INTEGER 0;
DECLARE afterCount INTEGER 0;
WHILE retryCount <= 10 DO
DECLARE EXIT HANDLER FOR SQLSTATE VALUE 'U11222'
BEGIN
/* This demonstrates how to pass data to the HANDLER in the SQL
special registers */
SET OutputRoot.XMLNSC.Top.WHILE.mySQLCODE = SQLCODE;
SET OutputRoot.XMLNSC.Top.WHILE.mySQLSTATE = SQLSTATE;
SET OutputRoot.XMLNSC.Top.WHILE.mySQLNATIVEERROR = SQLNATIVEERROR;
SET OutputRoot.XMLNSC.Top.WHILE.mySQLERRORTEXT = SQLERRORTEXT;
SET retryCount = retryCount + 1;
/* If we are an EXIT HANDLER, control is now passed to back to the
WHILE statement */
END;
/* In a real scenario this could be a PROPAGATE statement, and the exception
could be thrown by a 'downstream' node. In this case the HANDLER would
normally cope with a wider range of exception, for example, using LIKE '%' */
THROW USER EXCEPTION VALUES( -1, 'U11222', 42, 'error text' );
/* This is the next statement executed if it is a CONTINUE HANDLER */
SET afterCount = afterCount + 1;
END WHILE;
SET OutputRoot.XMLNSC.Top.WHILE.retryCount = retryCount;
SET OutputRoot.XMLNSC.Top.WHILE.afterCount = afterCount;
Bei EXIT (siehe oben) sieht die Ausgabe wie folgt aus:
<Top>
<WHILE>
<mySQLCODE>-1</mySQLCODE>
<mySQLSTATE>U11222</mySQLSTATE>
<mySQLNATIVEERROR>42</mySQLNATIVEERROR>
<mySQLERRORTEXT>error text</mySQLERRORTEXT>
<retryCount>11</retryCOUNT>
<afterCount>0</afterCOUNT>
</WHILE>
</Top>
Änderung von HANDLER in CONTINUE (DECLARE CONTINUE HANDLER FOR SQLSTATE VALUE
'U11222'); in diesem Fall lautet die Ausgabe wie folgt:
<Top>
<WHILE>
<mySQLCODE>-1</mySQLCODE>
<mySQLSTATE>U11222</mySQLSTATE>
<mySQLNATIVEERROR>42</mySQLNATIVEERROR>
<mySQLERRORTEXT>error text</mySQLERRORTEXT>
<retryCount>11</retryCOUNT>
<afterCount>11</afterCOUNT>
</WHILE>
</Top>
Der Unterschied wird in afterCount der Ausgabenachricht deutlich.-- Löschen Sie die Tabellen, damit sie nach der aktuellen Definition erneut erstellt werden können.
-- Wenn das Programm noch nie ausgeführt wurde, werden Fehler auftreten, da
-- nicht vorhandene Tabellen nicht gelöscht werden können. Diese Fehler werden ignoriert.
BEGIN
DECLARE CONTINUE HANDLER FOR SQLSTATE LIKE'%' BEGIN END;
PASSTHRU 'DROP TABLE Shop.Customers' TO Database.DSN1;
PASSTHRU 'DROP TABLE Shop.Invoices' TO Database.DSN1;
PASSTHRU 'DROP TABLE Shop.Sales' TO Database.DSN1;
PASSTHRU 'DROP TABLE Shop.Parts' TO Database.DSN1;
END;