Load n go Artikel der Ausgabe Februar / März 2012 und Teil 2
Es folgt der Download Code für Abonnenten:
Noch nicht Abonnent? Sonderaktion nutzen.
von Lynne Noll
Vor langer Zeit machte ich die Erfahrung, dass es ein Fehler ist, Programme einzeln und nacheinander zu erstellen. Wenn ich denselben Code an verschiedenen Stellen brauche, frage ich mich, ob ich eine Prozedur daraus machen sollte. Wenn der Code zwar nicht genau derselbe, aber doch sehr ähnlich ist, überlege ich, ob man vielleicht ein Utility daraus machen könnte.
Dynamisches SQL ist ein nützliches Werkzeug für Tools, kann aber abschreckend komplex wirken. Wenn man das Format der zurückgegebenen Daten nicht kennt, muss man mit Arrays und Pointern herumspielen und decodieren, wie die Datenformate aussehen. Ich hatte vor einigen Jahren schon einmal ein Tool veröffentlicht, das alle diese Funktionen abdeckt, und habe dieses Tool in der Zwischenzeit immer wieder erweitert. Inzwischen besteht es aus mehreren Teilen und ist ziemlich komplex. Dieses Tool leistet mehr als man für einfache Aufgaben benötigt, wie z.B. die Prüfung einer Kundennummer im Eingabebildschirm eines CL-Programms.
Viele Programmierer verwenden den Qshell-Befehl DB2 zum Ausführen von dynamischem SQL oder zum Ausführen von SQL-Abfragen in CL. Diese Technik ist zwar leistungsfähig und flexibel, aber sie kann nicht mit QTEMP arbeiten, akzeptiert keine Overrides und zwingt den Anwender zu Tricks, um überhaupt Daten zu empfangen.
Ich stelle in diesem Artikel drei einfache, leicht verständliche Utilities zur Verfügung, die mit dynamischem SQL arbeiten. Auch wer noch nie mit eingebettetem SQL gearbeitet hat, kann sie nachvollziehen:
-
ITSQL3RI übergibt einen Zähler.
-
ITSQL2RI übergibt ein Datenelement.
-
ITPRMPRI übergibt eine Auswahl aus einem universellen Suchfenster.
Falls die Tools Ihren Anforderungen nicht ganz entsprechen, sind sie leicht anpassbar. Sie sind komplett native, können mit Daten in QTEMP arbeiten, reagieren auf Overrides wie gewohnt und liefern ihre Ergebnisse über eine einfache Parameter-Schnittstelle. Aber sie können nicht alles. Jedes Utility erledigt eine Aufgabe in einfach anwendbarer Weise. Um Probleme mit unbekannten Datentypen und Pointern zu vermeiden, übergibt jedes Tool ein gut definiertes Datenelement.
Da die drei Tools auch für die Verwendung in CL-Programmen gedacht sind, sind sie als Programme realisiert, um Ihnen das Binden Ihrer CL-Programme zu ersparen. Das bedeutet, dass die Tools sowohl mit OPM RPG, CL und COBOL als auch mit RPG III und ILE RPG funktionieren. Die beiden Daten-Retrieval-Tools sind hauptsächlich für die Verwendung in CL gedacht, während das universelle Suchfenster überall praktisch ist.
Warum kann ich nicht einfach das Satzformat haben?
Häufig werde ich von Programmierern gefragt, wie man in SQL ein Satzformat abruft, das man vorher noch nicht kennt. Sie wollen das komplette Satzformat in einem zusammenhängenden Speicherbereich, um es dort zu verarbeiten.
Üblicherweise codiert man eine dynamische SQL-Abfrage auf eine bestimmte Tabelle mit einer Syntax wie Select * from MyTable und verarbeitet dann mit einer extern beschriebenen Datenstruktur das Ergebnis. Die Sortierfolge und die Where-Klausel können komplett dynamisch aufgebaut werden. Viele Programmierer haben das schon oft für flexible Abfrageprogramme auf bestimmte Datenbanktabellen, wie z.B. eine Auftragskopfdatei praktiziert. Um alle Felder in einem Datensatz abzurufen, kann man angeben:
Exec sql Fetch Cursor1 into :dsCursor1;
Aber obwohl es so aussieht, als ob SQL es ermöglicht, ein komplettes Satzformat abzurufen, wird eigentlich eine separate Variable für jedes zurückgegebene Feld erwartet. Der SQL-RPG-Precompiler löst alle Variablen in den deklarierten Datenstrukturen auf, auch in solchen, die auf die externe Beschreibung einer Datenbanktabelle referenziert sind. Obwohl es also so aussieht, als ob die SQL-Anweisung ein Satzformat abruft, ist das nur eine Illusion. Der Precompiler muss über eine bestimmte Datenstruktur kompilieren, die später verwendet werden soll; er kann nicht selbstständig zur Laufzeit die extern beschriebene Datenstruktur integrieren. Der Programmierer selbst kann das tun, wie ich in einem früher veröffentlichten Tool gezeigt habe, aber das ist mühsam und selten wirklich nötig.
Man braucht etwas, worauf man zählen kann
Da SQL über einen reichen Vorrat an Funktionen zur Typumwandlung und String-Manipulation verfügt, können SQL-Anweisungen so geschrieben werden, dass sie die Ergebnisdaten im erwarteten Format liefern. Daher kann ein Utility das passende Ergebnis liefern, auch wenn noch nicht vorher bekannt ist, welche Tabellen verwendet werden. Bei komplexen Anwendungen macht dieser Ansatz die SQL-Anweisung zu schwierig, aber bei einfachen Standardanwendungen funktioniert er tadellos.
Ein einfacher Anwendungsfall ist das Prüfen von Benutzereingaben. Normalerweise werden Benutzereingaben mit Werten in einer Stammdatei oder einer Prüfdatei abgeglichen. Wenn z.B. ein Benutzer eine Kundennummer eingibt, wird diese Nummer in der Kundenstammdatei gesucht. Andere denkbare Beispiele wären Firmen-, Abteilungs- oder Lagernummern. Eine Art, mit SQL zu prüfen, ob etwas existiert, ist das Abfragen eines Zählers: Ist das Ergebnis größer als Null, existiert das gesuchte Datenelement. Das Ergebnisformat eines Zählers ist bekannt: Eine Ganzzahl, die niemals NULL (im Sinne von „nichts“) ist. Das Tool ITSQL3RI (Abbildung 1) liefert diesen Zähler.
Das Utility liefert eine gepackte anstatt einer binären Ganzzahl, weil diese in CL leichter zu verarbeiten ist. Das CL-Programm stellt die SQL-Anweisung zusammen, übergibt sie an das Utility und erhält den Zähler und den SQL-Code zurück. (Wie immer bei SQL, müssen Sie auch hier SQL-Code oder SQL-State abfragen.) Falls ein Fehler auftritt, wird eine negative Eins (-1) als Zähler zurückgegeben.
Abbildung 2 zeigt ein Beispiel für ein CL-Programm, das mithilfe dieses Tools einen Zähler abfragt. Beachten Sie, dass in der Anweisung zum Zusammenstellen der SQL-Anweisung die einfachen Anführungszeichen verdoppelt werden, um sie als Bestandteil des Strings zu kennzeichnen. Sehen wir uns an, wie ITSQL3RI funktioniert: Im RPG-Code gibt es eine Variable namens ASTMT für die SQL-Anweisung, die dann im SQL-Code C1STMT heißt. Die Declare- und die Prepare-Anweisung beziehen sich auf den SQL-Namen, wobei die Prepare-Anweisung auch die RPG-Variable anspricht. So müssen dynamische, eingebettete SQL-Abfragen aufgebaut werden. Ein dynamisches SQL-Programm, das einen Cursor verarbeitet, muss den Cursor basierend auf dem Namen der Anweisung deklarieren, die Anweisung mithilfe der Programmvariablen vorbereiten, den Cursor öffnen und dann die Daten über den Cursor abrufen. Diese Schritte sind bei dynamischem SQL mit SELECT-Anweisungen immer gleich. Man kann nicht einfach, wie bei statischem SQL, eine Anweisung SELECT INTO benutzen. Da der Cursor mit ENDMOD deklariert wird, geht er verloren, wenn man zum aufrufenden Programm zurückkehrt, auch wenn das aufgerufene Programm nicht LR setzt oder den Cursor schließt.
Eine andere Möglichkeit, dieselbe Aufgabe zu lösen, bietet eine SQL-Anweisung etwa in der folgenden Form:
Select 1 from CustMaster if custnumber=12345;
Wenn kein Kunde mit der Nummer 12345 existiert, findet die SQL-Anweisung nichts und gibt den SQL-Code 100 zurück, was die Routine veranlasst, den Zähler mit dem Wert 0 zurückzugeben. Wenn der Kunde mit der Nummer 12345 existiert, gibt die Routine 1 zurück. Auch in diesem Fall prüft das CL-Programm nur, ob der Zähler 0 oder größer als 0 ist.
Es gibt noch mehr im Leben als Ganzzahlen!
Noch nicht Abonnent? Sonderaktion nutzen.
Versuchen Sie es selbst
Installieren Sie die Tools, und testen Sie sie in Ihrer eigenen Umgebung. Der Programmcode enthält die beiden RPG-Programme für die SQL-Abfrage-Tools ITSQL2RI und ITSQL3RI und für das Suchfenster, sowie die DDS für das Suchfenster und die Anwendungsdefinitions-Tabelle. Ich bin mir sicher, dass Sie den Nutzen dieser Tools schätzen werden. Wenn Sie sich in der Anwendung der Tools sicher fühlen, können Sie daran gehen, Sie für Ihre speziellen Anforderung anzupassen und nahtlos in Ihre Anwendungen zu integrieren.
Lynne Noll (lvwnoll@hotmail.com) arbeitet als Senior Programmer Analyst bei Vantage World Travel. Sie ist seit 1987 auf IBM i und den Vorgängermodellen tätig.
Übersetzt und für den deutschsprachigen Markt überarbeitet von Mathias Spateneder.