RPG und SQL sind seit geraumer Zeit eine gelungene Kombination – zumindest dann, wenn der Anwendungsentwickler das notwendige Verständnis der Datenbank mitbringt und zur zielgerichteten Auswahl der passenden Lösung in der Lage ist. Einzelsatzverarbeitung ist häufig ein Entscheidungskriterium für den nativen Lesezugriff mit RPG-Mitteln – also eine READ, READE oder CHAIN. Massendatenverarbeitungen sind indes meist mit SQL sinnvoll – weil performanter im Vergleich mit RPG-Lesezugriffen.

Mit Version 7.1 TR 7 bzw. Version 7.2 von IBM i wurde nun endlich das vollständige Free-Format RPG eingeführt. Die Vorzüge von Total free RPG liegen auf der Hand – kein Mischmasch mehr in den Anweisungen und für Entwicklerneulinge ein leichterer Einstieg in die RPG-Welt. Die mit Total free RPG eingeführten Erweiterungen machen sich auch im Zusammenspiel von SQL und RPG positiv bemerkbar. Darüber hinaus erleichtern einige nützliche neue Features dem Anwendungsentwickler die Arbeit deutlich – denn anstelle von bisher notwendigen APIs können wir nun mit SQL-Standards direkt auf Systemwerte, Konfigurationsinformationen und Ähnliches zugreifen.

Der Zugriff auf IBM i-Bereiche wird mit SQL über verschiedene Kategorien abgebildet. Dazu gehören:

  • Anwendungsservices
  • Kommunikationsservices
  • Java Services
  • Journal Services
  • Bibliotheksservices
  • Nachrichtenservices
  • Produktservices
  • PTF Services
  • Sicherheitsservices
  • Spool Services
  • Speicherservices
  • Überwachungsservices
  • Work Management Services

Diese Services lassen sich mittels SQL nutzen – allerdings nur dann, wenn auf Ihrem System ein bestimmter PTF-Stand installiert ist:

 

Wie man anhand dieser Auflistung sehen kann, stehen die unterschiedlichen SQL Services in den unterschiedlichsten SQL-Komponenten zur Verfügung. Das sind unter anderem Sichten, Tabellen, Prozeduren und andere.

Schauen wir uns dazu ein einfaches Beispiel zum Abrufen eines Systemwerts mit RPG und embedded SQL an:

Systemwerte lassen sich mit SQL über den Service SYSTEM_VALUE_INFO abrufen. Dabei ist allerdings zu beachten, dass beim Einsatz der Systemwert-Servicefunktion in SQL dieselben Berechtigungserfordernisse bestehen wie beim Arbeiten mit Systemwerten auf Befehlszeilenebene. Das bedeutet, dass man für bestimmte Systemwerte auch entsprechende Berechtigungen benötigt, um sie ansehen oder verändern zu können.

Der Aufbau der Systemwerte für SQL Services sieht wie folgt aus:

Schauen wir uns die SQL Services zunächst einmal generell hinsichtlich ihrer Funktion und ihres Einsatzspektrums an. Wie Sie anhand des nachfolgenden Beispiels sehen können, bedienen wir uns der SQL-Standards und nutzen eine SELECT-Anweisung, um den Inhalt der Systemwerte abzurufen. Nehmen wir als Beispiel den Systemwert QCTLSBSD.

Da sich der Service, wie in der Tabelle oben ersichtlich, in der Bibliothek QSYS2 befindet, verwende ich hier den qualifizierten Aufruf auf den Service (QSYS2.SYSTEM_VALUE_INFO), gefolgt vom Namen des Systemwerts:

SELECT * FROM QSYS2.SYSTEM_VALUE_INFO
WHERE SYSTEM_VALUE_NAME = 'QCTLSBSD'

Nach Ausführung des Aufrufs erhalten wir die Ergebnisanzeige:

Hier ist eine Anmerkung notwendig:

Der Einsatz von SQL und 5250 ist seit Jahren Praxis – aber mit den modernen Ansätzen in der Datenbank und dem „alten“ Datenstrom nicht mehr zu 100 Prozent vereinbar.

Ohne Anpassungen am Zeichensatz liefert eine SQL-Abfrage unter Nutzung der SQL Services folgendes Ergebnis:

Der Systemwertinhalt wurde korrekt ermittelt, kann aber in dem 5250-Standard-Anzeigemodus nicht korrekt wiedergegeben werden.

Deshalb wird für die Nutzung der SQL Services empfohlen, sie mit einem modernen SQL-Werkzeug einzusetzen und zum Beispiel auch zu debuggen. Dass dieses Verhalten in RPG beeinflussbar ist, werden wir später noch sehen – damit können Sie dann bedenkenlos die SQL Services auch in klassischen 5250-Anwendungen nutzen.

Hier noch ein Tipp zum allgemeinen Einsatz der SQL Services für die Systemwerte:
Sie können bei Bedarf auch Auflistungen von Systemwerten abrufen, indem Sie generische Werte eingeben. Schauen Sie sich dazu das folgende Beispiel an, in dem wir alle Systemwerte auflisten, die die Zeichenfolge „JOB“ beinhalten:

Hier verwende ich folgende Syntax:

SELECT * FROM QSYS2.SYSTEM_VALUE_INFO
WHERE SYSTEM_VALUE_NAME LIKE '%JOB%'

Aber kommen wir zurück zu RPG und dem Einsatz der SQL Services. Vielleicht haben Sie schon Erfahrungen damit gesammelt, mit Systeminformationen – wie zum Beispiel den Systemwerten in RPG – zu arbeiten. Dazu bietet IBM unter anderem spezielle APIs an. Auch für das Arbeiten mit Systemwerten steht ein solches API in Form von QWCRSVAL zur Verfügung. Allerdings ist das Codieren sehr speziell und erfordert ein nicht gerade unkompliziertes Verfahren. Einfacher geht es da mit den neuen SQL Services.

Im folgenden RPG-Beispiel nutzen wir wieder den Systemwert QCTLSBSD und wollen dessen Inhalt abfragen. In RPG wird auf die beiden möglichen Rückgabewerte der Systemwerte reagiert:

  1. Rückgabe eines Zeichenwerts
  2. Rückgabe eines numerischen Werts

Für beide Varianten sind Variablen definiert. Wie wir bereits in der Beschreibung des SQL-Systemwerteservices gesehen haben, wird der Inhalt als UCS-Wert verarbeitet. Also kümmern wir uns in dem RPG-Programm nun darum, dass die Zeichen in jedem Fall korrekt angezeigt werden. Und damit sind dann die Ergebnisse auch in der 5250-Anzeige erkennbar!

Nach der Ermittlung wird das Ergebnis angezeigt:

Der zugehörige Programmcode schaut folgendermaßen aus:

CTL-OPT ACTGRP(*NEW) COPYRIGHT('© H.J. Zeig ZeBIS 2016') ;

DCL-C Null -1;

Display();

*INLR = *ON;

// Prozedur Anzeige
DCL-PROC Display;

DCL-DS Daten;
Name VARCHAR(10);
w_Nummerisch INT(20);
CharUCS2Value VARUCS2(1280) CCSID(1200);
END-DS;

DCL-S w_NullInd INT(5) DIM(3);
DCL-S w_Charakter CHAR(50);

EXEC SQL SELECT SYSTEM_VALUE_NAME,
CURRENT_NUMERIC_VALUE,
CURRENT_CHARACTER_VALUE
INTO :Daten :w_NullInd
FROM QSYS2/SYSTEM_VALUE_INFO
WHERE SYSTEM_VALUE_NAME = 'QCTLSBSD';

// Zeichenumsetzung

w_Charakter = CharUCS2Value;

If w_NullInd(1) <> Null;
DSPLY Name;
Endif;

If w_NullInd(2) <> Null;
DSPLY w_Nummerisch;
Endif;

If w_NullInd(3) <> Null;
DSPLY w_Charakter;
Endif;

END-PROC Display;