Tritt bei der Ausführung eines SQL-Statements innerhalb eines (embedded) SQL-Programms ein Fehler auf, kommt es i. d. R. zu keinem Programm-Abbruch. Stattdessen wird ein SQLCODE und ein SQLSTATE ausgegeben, auf den man im Programm entsprechend reagieren kann. So weit so gut, nur welcher Fehler verbirgt sich hinter einem SQLCODE und wie kann man den zugehörigen Fehlertext ermitteln? In diesem Artikel wird gezeigt, mit welchen Mitteln man von dem SQLCODE zu der entsprechenden Fehler-Nachricht kommt.
SQLCODE oder SQLSTATE
Tritt bei der Ausführung eines SQL-Statements ein Fehler auf, wird sowohl ein SQLCODE als auch ein SQLSTATE ausgegeben. Bei dem SQLCODE handelt es sich um einen numerischen ganzzahligen Wert (Integer), während der SQLSTATE in der Form eines 5-stelligen alphanumerischen Werts ausgegeben wird.
In einem HLL-Programm werden sowohl SQLCODE als auch SQLSTATE über die SQL Communications Area (SQLCA) zurückgeliefert. In RPG wird die SQLCA vom SQL-Precompiler automatisch integriert. In anderen Programmiersprachen (z. B. COBOL oder C) muss die SQLCA mit einer INCLUDE-Anweisung eingebunden werden. Vielfach genügt es auch eine Variable SQLCODE (Integer) und/oder eine Variable SQLSTATE (Char(5)) zu definieren.
Die Ausgabe eines SQLCODEs ist die ursprüngliche Methode der IBM, um einen Fehler (in der DB2/400 jetzt Db2 for i) zurückzumelden. Im Fehlerfall wird ein negativer SQLCODE zurückgegeben und keine Datensätze ausgegeben. Wurde das SQL-Statement ordnungsgemäß ausgeführt, jedoch kein(e) Satz/Zeile gefunden, wird der SQLCODE 100 ausgegeben. Bei positiven SQLCODEs (außer 100) handelt es sich um Warnungen. Bei Warnungen wird das SQL-Statement jedoch ordnungsgemäß ausgeführt. Wird jetzt nur auf SQLCODE = 100 geprüft, werden Warnungen als Fehler behandelt! … und dann stellt sich die Frage, ob man das so will?
Bei dem SQLSTATE handelt es sich die Methode, die im SQL-Standard festgelegt wurde. Der SQLSTATE setzt sich aus einer 2-stelligen Klasse und einer 3-stelligen Sub-Klasse zusammen. Ob ein SQL-Statement ordnungsgemäß ausgeführt wurde oder nicht, zeigt sich in den ersten beiden Positionen, also der Klasse des SQLSTATEs. Klasse 00 bedeutet, dass das SQL-Statement ordnungsgemäß ausgeführt wurde. Klasse 01 heißt, dass eine Warnung ausgegeben wurde. Bei Klasse 02 wurde kein Satz/Zeile gefunden. Wurde im SQLSTATE irgendeine andere Klasse ausgegeben, handelt es sich um einen Fehler.
In der folgenden Abbildung werden die SQLCODE und SQLSTATE verglichen und die Unterschiede zwischen beiden aufgezeigt.

Da es sich bei dem SQLSTATE um die Standard-Methode handelt, und da die Datenbanken-Hersteller, wie auch die Programmierer einigen Spielraum bei der Vergabe der SQLSTATEs haben, müssen die SQLSTATEs und ihre Bedeutung in der Dokumentation der jeweiligen Datenbank nachgeschlagen werden.
Anders sieht es bei dem SQLCODE aus. Natürlich können auch hier die Fehlermeldungen für die unterschiedlichen SQLCODEs in den Dokumentationen (leider nur auf Englisch) nachgeschlagen werden.
Aber es gibt auch andere Methoden.
Message-File QSQLMSG
Wie alle Fehlermeldungen, die auf der IBM i ausgegeben werden, sind auch die SQL-Fehlermeldungen in einer Message-File, nämlich in der Message-File QSQLMSG in der Bibliothek QSYS (bzw. in der entsprechenden Sprachen-Bibliothek) hinterlegt.
Die Message-Id, unter der die Fehlermeldung hinterlegt ist, lässt sich einfach aus dem SQLCODE ermitteln. Die Message-Id setzt sich aus SQL oder SQ (je nachdem, ob der SQLCODE 5 oder weniger Ziffern hat) und dem Absolut-Wert des SQLCODES, ggf. linksbündig auf 4 Stellen mit Nullen (0) ausgefüllt, zusammen.
Die folgende Tabelle zeigt, wie der SQLCODE in eine Message-Id konvertiert werden kann:

Anmerkung:
Das funktioniert im Übrigen auch für den RPG-Status. Die RPG-Fehlermeldungen sind in der Message-File QRNXMSG hinterlegt. Status 102 (=Division durch 0) -> Message-Id RNX0102 in Message-File QRNXMSG
Mit diesen Informationen kann man nun einfach mit dem CL-Befehl WRKMSGF (Mit Nachr.dateien arbeiten) und dann der Auswahl 12 (= Mit Nachrichtenbeschreibungen arbeiten) die tatsächlichen Nachrichtentexte in Erfahrung bringen.
Das reicht natürlich, wenn man interaktiv schnell einen Fehlertext ermitteln will.
Muss man jedoch den Fehlertext innerhalb eines Programms oder einer SQL-Routine (Stored Procedure, Trigger, User Defined (Table) Function) ermitteln, kann man eine der folgenden Methoden verwenden:
- CL-Befehl RTVMSG:
Zunächst muss man die Message-Id ermitteln (s. o.). Im Anschluss daran, kann man den Message-Text mit dem CL-Befehl RTVMSG ermitteln. - API QMHRTVM (Retrieve Message):
Alternativ zu dem CL-Befehl RTVMSG kann man das System-API QMHRTV (Retrieve Message) einsetzten. Das API kann direkt in einem HLL-Programm aufgerufen werden. - View / Tabellen-Funktion MESSAGE_FILE_DATA:
Mit MESSAGE_FILE_DATA können Nachrichten-Daten können direkt mit SQL aus Message-Files ausgelesen werden.
Es muss also nur noch zuvor die Message-Id ermittelt werden und dann die Message-File QSQLMSG durchsucht werden. - Tabellen-Funktion SQLCODE_INFO in Bibliothek SYSTOOLS:
Mit der Tabellen-Funktion SQLCODE_INFO kann der Nachrichtentext direkt mit einem SQL SELECT-Statement ermittelt werden.
Dafür muss weder die Message-Id ermittelt noch eine Message-File angegeben werden. - SQL Befehl GET DIAGNOSTICS:
Mit GET DIAGNOSTIC können innerhalb des Programm-Codes viele Informationen über das zuvor ausgeführte SQL-Statement ermittelt werden.
Zu diesen Informationen gehören u. a. auch der Message-Text, sowie der SQLCODE und der SQLSTATE.
IBM Service MESSAGE_FILE_DATA – Message-File auslesen
MESSAGE_FILE_DATA wird sowohl als SQL-View als auch als Tabellen-Funktion bereitgestellt. Beide Objekte liefern die gleichen Daten. Die ausgegebenen Daten stimmen wiederum mit den Daten, die mit dem CL-Befehl DSPMSG (Nachrichten anzeigen) und/oder mit dem System-API QMHRCVM (Receive Nonprogram Message) ermittelt werden können, überein.
Mit der Tabellen-Funktion MESSAGE_FILE_DATA kann gezielt eine Message-File in einer Bibliothek durchsucht werden. Die Bibliothek, in der sich die Message-File befindet, und der Name der Message-File werden als Parameter übergeben.
Mit der View MESSAGE_FILE_DATA kann man alle Message-Files durchsuchen. Die Informationen aus den vorhandenen Message-Files werden zunächst alle ermittelt und im Anschluss entsprechend den WHERE-Bedingungen, gefiltert.
Sofern nur Daten aus einer einzigen Message-File durchsucht werden sollen, sollte aus Performance-Gründen die Tabellen-Funktion bevorzugt werden.
In dem folgenden Beispiel wird der Level1- und Level2-Text für den SQLCODE -811 (bzw. Message-Id SQL0811) aus der Message-File QSQLMSG in der QSYS ermittelt. Da auf diesem System Deutsch die System-Sprache ist, werden die Texte deutsch ausgegeben.

IBM Service SQLCODE_INFO – Vom SQLCODE zum Nachrichtentext
Wenn es nur darum geht den (Level1- und Level2-)Text für einen bestimmten SQLCODE zu ermitteln, kann die Tabellen-Funktion SQLCODE_INFO in der Bibliothek SYSTOOLS verwendet werden. Der SQLCODE wird direkt als Parameter an die Tabellen-Funktion übergeben.
Ausgegeben wird dann die entsprechende (SQL) Message-Id, sowie der Level1- und Level2-Text.
In dem folgenden Beispiel werden die Level1- und Level2-Texte für den SQLCODE -811 ermittelt.

GET DIAGNOSTICS
Sofern man innerhalb eines (Service-)Programms mit embedded SQL oder in einer SQL-Routine Informationen über zuvor ausgeführte SQL-Statements erhalten will, bietet sich der SQL-Befehl GET DIAGNOSTICS an.
Die über GET DIAGNOSTICS bereitgestellte Informationen werden mit Hilfe von vorgegebenen Konstanten-Werten (z. B. ROW_COUNT oder MESSAGE_TEXT) ausgelesen.
Die von GET DIAGNOSTICS bereitgestellte Informationen können den folgenden Bereichen zugeordnet werden:
- Statement-Informationen:
Liefern direkte Informationen über das zuvor ausgeführte SQL Statement.
Dazu gehören u. a.:- ROW_COUNT:
Anzahl der Zeilen, die durch ein INSERT-, UPDATE- oder DELETE-Statement hinzugefügt, geändert oder gelöscht wurden.
Anzahl der Zeilen, die bei einem multiple-Row-Fetch gelesen wurden. - DB2_NUMBER_RESULT_SETS:
Anzahl der Result-Sets, die durch die zuvor ausgeführte Stored Procedure zurückgegeben wurden.
- ROW_COUNT:
- Bedingungs-Informationen (Condition):
Liefern in erster Linie Informationen für fehlerhaft ausgeführte SQL-Statements.
CONDITION und ein Integer-Wert oder eine Konstante müssen als Teil der Syntax angegeben werden.
Zu den Bedingungs-Informationen gehören u. a.:- MESSAGE_TEXT:
Nachrichten-Text des zuvor ausgeführten SQL-Statements - DB2_RETURNED_SQLCODE:
Wird ohne SQLCA (SQL Communications Area) gearbeitet, kann der SQLCODE über DB2_RETURNED_SQLCODE ermittelt werden. - RETURNED_SQLSTATE:
Wird ohne SQLCA gearbeitet, kann der SQLSTATE über RETURNED_SQLSTATE ermittelt werden.
- MESSAGE_TEXT:
In dem folgenden Beispiel wird die Spalte PRICE (Preis) in der Tabelle ITEMMASTX für alle Artikel-Nr., die mit ABC beginnen um 2,5 % erhöht.
Tritt ein Fehler auf (SQLCODE < *ZEROS) wird der Fehlertext mit GET DIAGNOSTICS ermittelt und in die Variable ErrorText ausgegeben. Der ermittelte Fehlertext wird mit Hilfe des OpCodes DSPLY angezeigt.
Wurde das Update-Statement fehlerfrei ausgegeben, wird die Anzahl der geänderten Datensätze über GET DIAGNOSTICS und das Schlüssel-Wort ROW_COUNT ermittelt, in die Variable NbrRows ausgegeben und im Anschluss mit DSPLY angezeigt.

Nähere Informationen über das GET DIAGNOSTICS Statement findet man unter dem folgenden Link:
IBM i / 7.5.0 / GET DIAGNOSTICS statement
Soweit zu dem Thema, wie man aus dem SQLCODE im Fehler-Fall den tatsächlichen Fehler-Text ermitteln kann.
Und nun viel Spaß beim Ausprobieren!
Birgitta Hauser ist IBM Champion und Spezialistin für SQL- sowie RPG-Programmierung.
Frau Hauser gibt regelmäßig Workshops im Rahmen der MIDRANGE ACADEMY.
Sie schreibt regelmäßig für MIDRANGE und den TechKnowLetter. Hier erhalten Sie brandneue, tiefe Informationen zu SQL, RPG und vielem mehr.
Der TechKnowLetter erscheint monatlich. Sechs Ausgaben erhalten Sie für 88 Euro hier.