Anleitung für den IBM-i-Administrator
Etwa 20 Minuten. An Ihren Daten, Objekten und Programmen wird nichts verändert, es wird nichts installiert und kein fremder Code ausgeführt. Geschrieben wird ausschließlich in ein temporäres Verzeichnis (/tmp/export) und nach QTEMP; beides löschen Sie hinterher, QTEMP verschwindet von selbst. Sie brauchen eine SQL-Sitzung (ACS, STRSQL oder RUNSQL) und Leserecht auf die Bibliotheken, die untersucht werden sollen.
Der eine Schritt, auf den es ankommt
Die Katalogauszüge (Schritt 1 und 2) beschreiben Ihren Bestand: Bibliotheken, Dateien, Felder, Programme und das eingebettete SQL. Damit entsteht ein vollständiger Strukturbefund.
Was die Programme tun, steht in den Quellmembern — und die kommen erst mit Schritt 3. Ohne ihn liefert der Bericht Struktur ohne Logik, und die wichtigste Frage („zu welchem Programm gibt es keinen Quelltext mehr?") lässt sich nicht beantworten: es sähe so aus, als fehle er überall.
Der Bericht sagt Ihnen, wenn Schritt 3 gefehlt hat — aber ein zweiter Export kostet Sie wieder zwanzig Minuten.
In einer SQL-Sitzung ausführen. Die Tabellen entstehen in QTEMPund verschwinden mit der Sitzung — auf Ihrer Maschine bleibt nichts zurück.
-- Katalogauszüge. &LIB gegen Ihre Bibliothek tauschen; für mehrere
-- Bibliotheken den Block je Bibliothek wiederholen oder IN ('LIB1','LIB2').
--
-- WICHTIG: dieser Block UND der CPYTOIMPF-Block darunter gehören in
-- DIESELBE Sitzung. QTEMP gehört zum Job -- wer die Abfragen in ACS
-- laufen lässt und die Kopierbefehle danach auf einer 5250-Befehlszeile,
-- findet dort nichts mehr. Läuft beides getrennt, ersetzen Sie QTEMP
-- durch eine eigene Bibliothek (nicht QGPL) und räumen sie hinterher auf.
DROP TABLE QTEMP/EXPBIB;
CREATE TABLE QTEMP/EXPBIB AS (
SELECT SCHEMA_NAME, SCHEMA_TEXT
FROM QSYS2.SYSSCHEMAS
WHERE SCHEMA_NAME IN ('&LIB')
) WITH DATA;
DROP TABLE QTEMP/EXPTAB;
CREATE TABLE QTEMP/EXPTAB AS (
SELECT TABLE_SCHEMA, SYSTEM_TABLE_NAME, TABLE_NAME, TABLE_TEXT, TABLE_TYPE
FROM QSYS2.SYSTABLES
WHERE TABLE_SCHEMA IN ('&LIB')
) WITH DATA;
DROP TABLE QTEMP/EXPSPA;
CREATE TABLE QTEMP/EXPSPA AS (
SELECT TABLE_SCHEMA, TABLE_NAME, SYSTEM_COLUMN_NAME, COLUMN_NAME,
DATA_TYPE, LENGTH, NUMERIC_SCALE, IS_NULLABLE, COLUMN_TEXT, CCSID
FROM QSYS2.SYSCOLUMNS
WHERE TABLE_SCHEMA IN ('&LIB')
) WITH DATA;
-- OBJECT_STATISTICS liefert auch LAST_USED_TIMESTAMP: wann ein Objekt
-- zuletzt BENUTZT wurde. Das beantwortet die Frage nach ungenutzten
-- Programmen -- und es gibt sie auf keinem anderen System.
DROP TABLE QTEMP/EXPOBJ;
CREATE TABLE QTEMP/EXPOBJ AS (
SELECT OBJLIB, OBJNAME, OBJTYPE, OBJATTRIBUTE, OBJTEXT, OBJOWNER,
CHANGE_TIMESTAMP, LAST_USED_TIMESTAMP
FROM TABLE(QSYS2.OBJECT_STATISTICS('&LIB', '*ALL')) AS O
) WITH DATA;
-- Eingebettetes SQL -- steht IM Programmobjekt und ist damit auch dann
-- lesbar, wenn der Quelltext fehlt.
DROP TABLE QTEMP/EXPSQL;
CREATE TABLE QTEMP/EXPSQL AS (
SELECT PROGRAM_SCHEMA, PROGRAM_NAME, STATEMENT_NUMBER, STATEMENT_TEXT
FROM QSYS2.SYSPROGRAMSTMTSTAT
WHERE PROGRAM_SCHEMA IN ('&LIB')
) WITH DATA;Es sind genau die Sichten, die auch eine spätere Live-Anbindung abfragen würde. Wer den Export prüfen will, sieht an jeder Spalte, woher sie kommt.
ADDCOLNAM(*SQL) schreibt die Spaltennamen in die Kopfzeile — ohne sie ist die Datei nicht zuzuordnen. STMFCCSID(1208) ist UTF-8; ohne diese Angabe kommen Umlaute als Datenmüll an.
/* Als CSV in den IFS schreiben. Verzeichnis vorher anlegen: */
/* MKDIR DIR('/tmp/export') */
/* MKDIR DIR('/tmp/export/quelltext') */
CPYTOIMPF FROMFILE(QTEMP/EXPBIB) TOSTMF('/tmp/export/bibliotheken.csv') +
MBROPT(*REPLACE) STMFCCSID(1208) RCDDLM(*CRLF) +
DTAFMT(*DLM) STRDLM(*DBLQUOTE) ADDCOLNAM(*SQL)
CPYTOIMPF FROMFILE(QTEMP/EXPTAB) TOSTMF('/tmp/export/tabellen.csv') +
MBROPT(*REPLACE) STMFCCSID(1208) RCDDLM(*CRLF) +
DTAFMT(*DLM) STRDLM(*DBLQUOTE) ADDCOLNAM(*SQL)
CPYTOIMPF FROMFILE(QTEMP/EXPSPA) TOSTMF('/tmp/export/spalten.csv') +
MBROPT(*REPLACE) STMFCCSID(1208) RCDDLM(*CRLF) +
DTAFMT(*DLM) STRDLM(*DBLQUOTE) ADDCOLNAM(*SQL)
CPYTOIMPF FROMFILE(QTEMP/EXPOBJ) TOSTMF('/tmp/export/objekte.csv') +
MBROPT(*REPLACE) STMFCCSID(1208) RCDDLM(*CRLF) +
DTAFMT(*DLM) STRDLM(*DBLQUOTE) ADDCOLNAM(*SQL)
CPYTOIMPF FROMFILE(QTEMP/EXPSQL) TOSTMF('/tmp/export/sql-im-programm.csv') +
MBROPT(*REPLACE) STMFCCSID(1208) RCDDLM(*CRLF) +
DTAFMT(*DLM) STRDLM(*DBLQUOTE) ADDCOLNAM(*SQL)
/* Enthält eine Bibliothek kein Programm mit eingebettetem SQL, bleibt */
/* EXPSQL leer, und der letzte Befehl bricht mit CPF2803/CPF2817 ab. */
/* Das ist in Ordnung: schicken Sie den Export ohne diese eine Datei. */Der Schritt aus dem Kasten oben. Ohne ihn gibt es keine Programmlogik im Befund. Er läuft in zwei Teilen: erst lässt SQL die Kopierbefehle erzeugen, dann arbeitet eine Zeile in QShell sie ab. Es entsteht dabei kein Objekt auf Ihrer Maschine — kein CL-Programm, nichts, was kompiliert werden müsste.
/* --- 3a: die Befehle erzeugen lassen ----------------------------- */
/* In DERSELBEN SQL-Sitzung wie Schritt 1. Das Ergebnis ist eine */
/* Textdatei mit je einem Befehl pro Zeile -- niemand tippt hier etwas. */
DROP TABLE QTEMP/EXPCMD;
CREATE TABLE QTEMP/EXPCMD AS (
SELECT BEFEHL FROM (
SELECT 1 AS FOLGE,
'MKDIR DIR(''/tmp/export/quelltext/' || TRIM(P.TABLE_SCHEMA) ||
'/' || TRIM(P.TABLE_NAME) || ''')' AS BEFEHL
FROM QSYS2.SYSPARTITIONSTAT P
JOIN QSYS2.SYSTABLES T ON T.TABLE_SCHEMA = P.TABLE_SCHEMA
AND T.TABLE_NAME = P.TABLE_NAME
AND T.FILE_TYPE = 'S'
WHERE P.TABLE_SCHEMA IN ('&LIB')
GROUP BY P.TABLE_SCHEMA, P.TABLE_NAME
UNION ALL
SELECT 2,
'CPYTOSTMF FROMMBR(''/QSYS.LIB/' || TRIM(P.TABLE_SCHEMA) || '.LIB/' ||
TRIM(P.TABLE_NAME) || '.FILE/' || TRIM(P.TABLE_PARTITION) ||
'.MBR'') TOSTMF(''/tmp/export/quelltext/' || TRIM(P.TABLE_SCHEMA) ||
'/' || TRIM(P.TABLE_NAME) || '/' || TRIM(P.TABLE_PARTITION) || '.' ||
COALESCE(NULLIF(TRIM(P.SOURCE_TYPE), ''), 'TXT') ||
''') STMFOPT(*REPLACE) STMFCCSID(1208) ENDLINFMT(*LF)'
FROM QSYS2.SYSPARTITIONSTAT P
JOIN QSYS2.SYSTABLES T ON T.TABLE_SCHEMA = P.TABLE_SCHEMA
AND T.TABLE_NAME = P.TABLE_NAME
AND T.FILE_TYPE = 'S'
WHERE P.TABLE_SCHEMA IN ('&LIB')
) X ORDER BY FOLGE
) WITH DATA;
/* Als reine Textdatei ausschreiben. DTAFMT(*FIXED) ist hier wichtig: */
/* es schreibt weder Anführungszeichen noch eine Kopfzeile hinein. */
CPYTOIMPF FROMFILE(QTEMP/EXPCMD) TOSTMF('/tmp/export/befehle.txt') +
MBROPT(*REPLACE) STMFCCSID(1208) RCDDLM(*LF) DTAFMT(*FIXED)Jetzt die erzeugte Liste abarbeiten — in QShell (STRQSH).
/* --- 3b: die Befehle abarbeiten -------------------------------- */ /* In QShell (Befehl STRQSH). Zwei Zeilen, sonst nichts. */ mkdir -p /tmp/export/quelltext/&LIB while read -r c; do system "$c" </dev/null; done < /tmp/export/befehle.txt
Zwei Kleinigkeiten, an denen es sonst scheitert
Das </dev/null hinter system ist nicht optional. Ohne es liest der Befehl selbst aus der Liste, die die Schleife gerade abarbeitet — und nach wenigen Zeilen ist Schluss. An einer echten Maschine gemessen: mit der Angabe 965 von 965 Zeilen, ohne sie 24.
MKDIR legt keine übergeordneten Verzeichnisse an. Deshalb steht das mkdir -p davor — sonst laufen alle Befehle durch und es entsteht keine einzige Datei.
Fehlt zu einem Programm das Member, ist das kein Fehler — es ist der Befund, um den es geht. Er landet in Anhang A des Berichts.
✓ Richtig
export.zip
├── bibliotheken.csv
├── tabellen.csv
├── spalten.csv
├── objekte.csv
├── sql-im-programm.csv
└── quelltext/
├── KREDIT/
│ ├── QRPGLESRC/
│ │ ├── KRD001.RPGLE
│ │ └── KRD002.RPGLE
│ └── QCLSRC/
│ └── KRD003.CLLE
└── KUNDEN/
└── QRPGLESRC/
└── KDS001.RPGLEDer Membername ist der Dateiname. Über ihn wird das Programmobjekt zugeordnet.
✗ Nicht ausreichend
export.zip ├── bibliotheken.csv ├── tabellen.csv ├── spalten.csv ├── objekte.csv └── sql-im-programm.csv
Kein quelltext/. Der Bericht sagt das ausdrücklich — aber er kann dann nur Struktur und eingebettetes SQL auswerten.
Packen mit ZIP aus QShell oder über eine Netzwerkfreigabe vom Arbeitsplatz aus. Bis 200 MB entpackt.
TABLE_SCHEMA, OBJNAME …). Fehlen sie, wurde ADDCOLNAM(*SQL) vergessen.tabellen.csv und suchen Sie einen Objekttext mit Umlaut. Steht dort Datenmüll, fehlte STMFCCSID(1208).quelltext/ ungefähr so viele Dateien wie Programme in objekte.csv? Große Abweichungen sind ein Befund — aber prüfen Sie, ob nicht einfach eine Quelldatei vergessen wurde.Wird gelesen
Wird nicht gelesen
Nein. Sie führen Katalogabfragen und Kopierbefehle aus, beides IBM-Bordmittel. Von uns kommt kein Code auf Ihre Maschine, und wir bekommen keinen Zugang zu ihr.
Nein. Der Export beschreibt Struktur und Programme — Bibliotheken, Dateien, Felder, Quelltext. Die Sätze in Ihren Dateien sind nicht enthalten; keine der Abfragen liest sie.
Dann ist der Befund für Sie besonders wertvoll — genau das ist die Frage, die er beantwortet. Der Bericht listet die betroffenen Programme in Anhang A und nennt für jedes, welche Dateien es laut eingebettetem SQL anfasst. Das steht im Objekt, ist also auch ohne Quelltext lesbar.
Weil die schneller versprochen als eingerichtet ist. Netzwerkfreigabe, Benutzerprofil, Change-Genehmigung, Sicherheitsprüfung — in einem regulierten Haus sind das Wochen. Der Export beantwortet die erste Frage ohne all das. Wenn Sie danach weitermachen wollen, ist die Verbindung der nächste Schritt, nicht der erste.
Nehmen Sie alle mit, die fachlich zusammengehören. Der Bericht zeigt in Abschnitt 7, welche Bibliothek an welcher hängt — und das geht nur, wenn beide Seiten im Export liegen. Fehlt eine, erscheint der Bezug als „Ziel nicht im Export enthalten“.
Bis 200 MB entpackt. Katalogauszüge sind klein; die Größe kommt aus den Quellmembern. Ein Bestand mit zweitausend Programmen liegt erfahrungsgemäß deutlich darunter.