| Der Exception-Teil eines PL/SQL Blocks |
|
|
| Donnerstag, 16. Oktober 2008 um 14:47 | ||||
|
PL/SQL hat ein mächtiges Konzept zur Behandlung von Fehlern, bzw. Ausnahmen in Programmen. Es ist tatsächlich möglich, stabile Programme zu realisieren, die “abschusssicher” sind und Fehler in der Datenbank oder die Nutzung der Datenbank sichern. Die Ausnahmebehandlung ist ereignisbasierend. Alles, was getan werden muß, ist eine Ausnahmebedingung zu formulieren und schon wird, wann immer diese Bedingung zutrifft, der entsprechende Ausnahmebehandlungsteil, den Sie ebenfalls selbst formulieren, aufgerufen. Ein PL/SQL Block besteht bekanntlich aus mehreren Teilen: dem Deklarationsteil, dem ausführbaren Teil und dem Fehlerbehandlungsteil (exception section). Wenn ein Fehler im ausführbaren Teil des Blockes auftritt, wird die Programmkontrolle an den Exception Teil übergeben. PL/SQL durchsucht den Exception Teil nach einer Behandlung für den aufgetretenen Fehler. Ein Fehler gilt als behandelt, wenn im Exception Teil ein sogenannter Exception Handler existiert. Das bedeutet, wenn es eine WHEN Klausel gibt, die der aufgetretenen Ausnahme (=Fehler) entspricht. Wenn dies zutrifft, werden die ausführbaren Anweisungen des Exception Handlers ausgeführt. Wenn es keine Behandlung gibt, aber eine WHEN OTHERS Klausel existiert, werden die hier formulierten Anweisungen ausgeführt. Wenn keine der obigen Bedingungen zutrifft, gilt die Ausnahme als unbehandelt und der Fehlercode mitsamt dem Fehlertext wird “hochgereicht”, im einfachsten Fall also dem Benutzer präsentiert. Es gibt vier Typen von Exceptions.
Benannte System ExceptionsBeispiele für benannte Systemfehler sind z.B. NO_DATA_FOUND, DUP_VAL_ON_INDEX oder ZERO_DIVIDE-Ausnahmen. (die benannten Exceptions findet man am besten in der ORACLE Dokumentation. Sie sind allerdings nur ein ganz kleiner Teil der möglichen Fehler, die die Datenbank zurückliefern kann) Beispiel:
Benannte, durch den Programmierer definierte ExceptionsHier haben wir ein Beispiel für eine durch den Programmierer benannte Exception. Ich habe eine Exception erzeugt mit Namen no_sales. Im ausführbaren Teil löse ich die Ausnahme explizit aus. Die Ausführung wird sofort im Exception Teil fortgesetzt.
Die Ausnahme wird im Deklarationsteil definiert. Im ausführbaren Teil steht nur die Anweisung zum Auslösen der Ausnahme. PL/SQL durchsucht nun den Exception Teil nach dem Exception Handler der Ausnahme und führt die Anweisungen für den Handler aus (die NULL-Anweisung). Damit gilt der Fehler, oder die Ausnahme als behandelt. Unbenannte System ExceptionsWenn ein interner Fehler auftritt (bspw. Ein Extent kann nicht angelegt werden oder eine Berechtigung zur Manipulation von Tabellen fehlt), liefert ORACLE den entspr. Fehler, der anhand seiner Fehlernummer identifiziert wird. PL/SQL stellt hier keine vordefinierten Fehler zur Verfügung. Wir können aber einen eigenen Handler für solche Fehler schreiben. Dazu bindet man den ORACLE-Fehler an eine im Programm deklarierte Ausnahme. Das geschieht mit dem Pragma EXCEPTION_INIT.
Das Beispiel ist nicht sinnvoll, zeigt jedoch das Binden der Fehler: ORACLEs? Fehler -00001 ist der Fehler “duplicate values found”, der bspw. beim Verletzen eines Unique Constraints auftritt. Wann immer dieser Fehler im ausführbaren Teil auftritt, wird der Exception Handler angesprungen. Das Beispiel zeigt, dass Sie aber nach wie vor solche Fehler auch selbst mit RAISE auslösen können. Sinnvoll ist das Beispiel deshalb nicht, weil es für den Fehler -00001 bereits eine von ORACLE vordefinierte Ausnahme gibt: DUP_VAL_ON_INDEX. Verhalten und PropagationWenn eine Ausnahme in einem Block deklariert wird, ist sie lokal innerhalb des Blocks, aber global für alle Blöcke, die durch den Block umschlossen werden. Alle lokal deklarierten Ausnhamen haben Vorrang gegenüber den System Exceptions. Das bedeutet, wenn Sie eine Ausnahme no_data_found erzeugen, ersetzt diese Ausnahme das Standard-Verhalten der System Exception gleichen Namens. Es ist also keine gute Idee, eigene Ausnahmen genauso zu nennen, wie vordefinierte Exceptions. Wenn eine Ausnahme ausgelöst wurde, sucht PL/SQL den entsprechenden Handler im aktuellen Block. Wird der Fehler dort nicht behandelt, propagiert PL/SQL den Fehler in den übergeordneten Block. Wird der Fehler auch hier nicht behandelt, wird weiterpropagiert. Gibt es keine weiteren Blöcke, in die “hinaufgereicht” werden kann, erhält der Benutzer einen unbehandelten Ausnahme-Fehler. Exceptions auslösenAusnahmen werden automatisch ausgelöst, wenn ein Datenbankfehler oder PL/SQL-Fehler auftritt. Sie können aber auch explizit vom Entwickler ausgelöst werden mit Hilfe des RAISE Statements. Gleichermaßen kann der Entwickler die Prozedur RAISE_APPLICATION_ERROR nutzen, um Fehler an die Client-Applikation zu melden. Exceptions behandelnWurde eine Ausnahme ausgelöst, bricht die normale Programmausführung ab und der Exception Teil erhält die Programmkontrolle. Aus dem Exception Teil ist es nicht möglich, in den ausführbaren Teil zurückzukehren. Das scheint eine enorme Einschränkung zu sein, lässt sich aber über geschachtelte Blöcke umgehen. Wenn Sie die WHEN OTHERS Klausel im Exception Teil nutzen, muß dies der letzte Handler im Exception Teil sein. Denn PL/SQL scannt den Exception Teil von oben nach unten nach dem passenden Handler durch. Da WHEN OTHERS auf jede Form von Ausnahme reagiert, würden dahinterstehende Handler niemals angesprungen werden. Unbehandelte ExceptionsWenn eine Ausnahme ausgelöst wird und es keinen Handler im Exception Teil gibt, wird dies als unbehandelte Ausnahme bezeichnet und propagiert. Eine Anwendung mit gutem Design wird einen WHEN OTHERS Teil haben, um auch unerwartete Ausnahmen abzufangen. Es gibt zwei Standards, die es erlauben, zu prüfen, welcher Fehler aufgetreten ist: SQLCODE und SQLERRM. SQLCODE und SQLERRMDie Funktion SQLCODE wird genutzt, um die Fehlernummer der letzten aufgetretenen Ausnahme zu ermitteln. Die Funktion SQLERRM erhält als Argument die Fehlernummer und liefert den dazugehörenden Fehlertext.
RAISE_APPLICATION_ERRORDie RAISE_APPLICATION_ERROR Prozedur ist der einzige Weg, Fehler an die Client-Applikation zu senden. Sie wird häufig genutzt, um mit Hilfe von Triggern Datenbankfehler an den Client zu melden. Die Prozedur wird mit zwei Argumenten aufgerufen. Das erste Argument ist die Fehlernummer (Nummern zwischen -20001 und -21000 stehen zur freien Verfügung), das zweite Argument ein beliebiger Fehlertext. Unmittelbar nach Aufruf der Prozedur bricht das Programm ab. Beispiel
Übersteuerte AusnahmenSystemausnahmen müssen eigentlich nicht deklariert werden, da sie ja bereits deklariert sind, sobald PL/SQL ausgeführt wird. Wenn man jedoch – warum auch immer – eine eigene Ausnahme mit dem gleichen Namen wie eine Systemausnahme deklarieren will, ist dies möglich. Die benutzerdefinierte Ausnahme übersteuert die Systemausnahme.
Diese Ausnahme übersteuert die Systemausnahme. Sie wird nicht mehr ausgelöst, wenn ein doppelter Wert in eine Spalte mit einem UNIQUE INDEX eingefügt wird, was ja das normale Verhalten wäre. Ausnahmen qualifizierenWenn Sie also aus irgendwelchen sadistischen Gründen eine benutzerdefinierte Ausnahme gleich einer Systemausnahme benennen, übersteuert diese die Systemausnahme. Trotzdem ist es möglich, zwischen beiden Ausnahmen zu unterscheiden. Sie müssen dazu lediglich genauer qualifiziert werden.
Das obere Beispiel unterscheidet also zwischen der benutzerdefinierten und der Systemausnahme und erlaubt es PL/SQL, den richtigen Fehlerbehandlungsteil zu finden. Aber das Übersteuern von Systemausnahmen ist generell eine schlechte Idee, also denken wir gar nicht erst an mögliche Konsequenzen und, schlimmer noch, an das aufwendige Debuggen.
|
||||


Kommentare
Ich finde das hier sehr gut beschrieben.
,mfg Zitieren
Alle Kommentare dieses Beitrages als RSS-Feed.