CCSID und Codepage – Zeichencodierung auf IBM i (AS/400)

1. Einleitung

Wer auf einer IBM i arbeitet, begegnet früher oder später den Begriffen Codepage und CCSID. Meistens dann, wenn Umlaute falsch dargestellt werden, Sonderzeichen verschwinden oder beim Datenaustausch mit Windows, Linux und anderen Systemen unerwartete Zeichen erscheinen. Die Ursache liegt häufig nicht in den Daten selbst, sondern in deren Interpretation.

2. Was ist eine Codepage?

Der Computer speichert keine Buchstaben, sondern numerische Werte. Eine Codepage legt fest, welchen Codewert ein bestimmtes Zeichen besitzt.
Historisch sind zwei Codierungsfamilien besonders wichtig:
  • ASCII1: vor allem auf PCs und Unix-Systemen verbreitet
  • EBCDIC2: traditionell auf IBM-Grossrechnern und IBM-i verwendet
Hier 2 Beispiele:
Grossbuchstabe A     Codierung                   Hexadezimal     Dezimal
                     ASCII                       41              65
                     EBCDIC (Codepage 500)       C1              193
                     UTF-8                       41              65
Leerzeichen (Space)  ASCII                       20              32
                     EBCDIC (Codepage 500)       40              64
                     UTF-8                       20              32
Ein EBCDIC-Text kann deshalb nicht einfach als ASCII interpretiert werden. Die Daten müssen passend konvertiert werden.

3. Was ist eine CCSID?

CCSID bedeutet «Coded Character Set Identifier»3
Während eine Codepage die Zuordnung von Zeichen zu Codewerten beschreibt, definiert die CCSID bei IBM die verwendete Zeichencodierung, einschliesslich des Zeichensatzes und der zugehörigen Codierungsregeln. In der Codepage werden auch Länder-, Regionen- und Spracheigenheiten berücksichtigt.
Typische CCSIDs auf IBM i sind:
CCSID   Bedeutung
37      EBCDIC, USA/Kanada
273     EBCDIC, Deutschland
500     EBCDIC, international
1141    EBCDIC, Deutschland mit Eurozeichen
1208    Unicode UTF-8
13488   Unicode UTF-16
65534   Keine zugeordnete Zeichencodierung; keine normale (automatische) Textkonvertierung möglich (*MSG)
65535   Keine zugeordnete Zeichencodierung; keine normale (automatische) Textkonvertierung möglich (*HEX)
CCSID 65535 ist eine Altlast. Ihre Besonderheiten werden weiter unten beleuchtet.

4. CCSID auf IBM i

Auf IBM i können unterschiedliche CCSIDs gleichzeitig vorkommen, beispielsweise auf folgenden Ebenen:
- Systemwert          DSPSYSVAL SYSVAL(QCCSID)
- Benutzerprofil      DSPUSRPRF USRPRF(MYUSER) TYPE(*BASIC)  
- Job                 DSPJOB OPTION(*DFNA)
- Datenbankfeld       DSPFFD FILE(MYLIB/MYFILE)
- Quellenteildatei    DSPFD FILE(MYLIB/QRPGLESRC) TYPE(*ATR)
- Files im IFS        DSPATR OBJ('/home/MYLIB/MYFILE.txt')
Auf Datenbank-Feldebene kann man sich die Informationen auch per SQL anzeigen lassen:
SQL
SELECT
    ORDINAL_POSITION,
    SUBSTR(COLUMN_NAME, 1, 10) COLUMN_NAME,
    DATA_TYPE,
    LENGTH,
    CCSID
FROM QSYS2.SYSCOLUMNS
WHERE TABLE_SCHEMA = 'MYLIB'
  AND TABLE_NAME   = 'MYFILE'
ORDER BY 1;
Bei Datenbankoperationen kann IBM i zwischen unterschiedlichen CCSIDs automatisch konvertieren, sofern deren Codierungen bekannt und die Zeichen darstellbar sind. Gerade diese automatische Umsetzung ist eine Stärke der Plattform.

5. Typische Probleme in der Praxis

Unterschiedliche CCSIDs

Schreibt ein Programm Text aus einer Umgebung mit CCSID 273 in ein Datenbankfeld mit CCSID 37, nimmt IBM i die nötige Konvertierung selbst vor. Wird dagegen eine falsche CCSID deklariert, können Sonderzeichen verfälscht werden.

Datenaustausch mit Windows und Linux

Für CSV-Dateien oder Schnittstellen wird heute häufig UTF-8 erwartet. Ein Export kann beispielsweise so erfolgen:
CMD
CPYTOIMPF FROMFILE(MYLIB/MYFILE)
          TOSTMF('/home/export.csv')
          STMFCCSID(1208)
          RCDDLM(*CRLF)
Damit wird die Ausgabedatei mit CCSID 1208 (UTF-8) erstellt. Voraussetzung ist, dass die Quell-Textfelder richtig deklariert sind und damit sinnvoll konvertiert werden können.

RPG und SQL

Auch RPG-Programme und SQL-Anweisungen sind von CCSID-Unterschieden betroffen. Besonders bei der Kombination von EBCDIC-Feldern, Unicode-Daten und externen Schnittstellen muss klar sein, welche CCSID die einzelnen Operanden verwenden. Eine falsche Zeichencodierung wird nicht dadurch korrigiert, dass man lediglich eine andere CCSID zuweist. Die tatsächlich enthaltenen Daten müssen gegebenenfalls konvertiert werden.

6. CCSID 65535 – eine typische Altlast

Bei älteren AS/400-Anwendungen begegnet man häufig CCSID 65535. Sie signalisiert, dass den Files/Feldern/Bytes keine bestimmte Zeichencodierung zugeordnet wurde und deshalb die übliche automatische Textkonvertierung unterbleibt. Das bedeutet nicht zwangsläufig, dass die gespeicherten Daten tatsächlich binär sind. Oft enthalten solche Felder ganz gewöhnlichen EBCDIC-Text. Die Definition sagt lediglich nicht, nach welcher Codepage dieser Text interpretiert werden kann.

Warum wurde 65535 verwendet?

Dafür gab und gibt es verschiedene Gründe:
  • Man wollte automatische Zeichenkonvertierungen vermeiden
  • Die Anwendung arbeitete ausschliesslich in einer homogenen EBCDIC-Umgebung
  • Einzelne Felder enthielten Text und binäre Inhalte
  • Bestehende Programme sollten unverändert weiterlaufen
Solange die Daten ausschliesslich innerhalb der gewohnten IBM-i-Umgebung verwendet werden, fallen diese Nachteile kaum auf.

CCSID 65534 und 65535 in IBM-Objekten

Die Default-CCSID von Message Queues, Job Message Queues, System Reply Lists und History Logs ist 65534. Dieser Wert wird auch *MSG oder *MSGD genannt.
Die Default-CCSID von Message-Files ist 65535. Dieser Wert wird auch *HEX genannt.

Wo entstehen heute Schwierigkeiten?

Ein Beispiel: Eine Kundendatei enthält Namen und Adressen in einem alphanumerischen Feld mit CCSID 65535. Tatsächlich sind die Bytes jedoch nach der deutschen EBCDIC-Codepage codiert.
Ein älteres RPG-Programm zeigt die Namen korrekt an, weil es dieselbe Interpretation der Bytes voraussetzt. Eine neue Webanwendung liest die Daten über eine SQL-Schnittstelle und erwartet UTF-8.
Da die Felddefinition keine verwertbare Text-CCSID liefert, bleibt die automatische Konvertierung aus. Das Resultat: unlesbare Zeichen oder fehlerhafte Umlaute oder Sonderzeichen.4

Wie lässt sich das Problem lösen?

Der erste Schritt ist die Untersuchung der tatsächlich gespeicherten Bytes und der bisher verwendeten Codierung. Erst danach lässt sich festlegen, wie die Inhalte korrekt zu interpretieren und bei Bedarf in eine neue CCSID zu konvertieren sind. Für neue Schnittstellen bietet sich häufig eine gezielte Konvertierung in UTF-8 an. Bei bestehenden Datenbankdateien kann es langfristig sinnvoll sein, Textfelder mit ihrer tatsächlichen CCSID zu definieren. Dabei ist Vorsicht geboten: Die blosse Neudeklaration einer CCSID ist keine Datenbereinigung. Eine Änderung der Felddefinition oder der zugrunde liegenden Bytes kann Auswirkungen auf RPG-Programme, Sortierungen, Vergleiche, Datenbankzugriffe und Schnittstellen haben. CCSID 65535 ist nicht grundsätzlich falsch. Für echte Binärdaten oder bewusst unverändert zu übertragende Bytes kann sie sinnvoll sein. Für gewöhnliche Textfelder ist sie dagegen oft ein grosser Knackpunkt.
Beim Systemwert QCCSID verdient der Wert 65535 besondere Aufmerksamkeit: Bei einer Modernisierung sollten die tatsächlich eingesetzten Job- und Feld-CCSIDs sowie die beteiligten Schnittstellen geprüft werden, statt die Systemeinstellung unbesehen zu verändern.

7. Unicode – die moderne Alternative

Unicode definiert einen universellen Zeichensatz für praktisch alle heute gebräuchlichen Schriftzeichen. Zu den verbreiteten Codierungsformen gehören UTF-85 und UTF-166. UTF-8 benötigt je nach Zeichen ein bis vier Bytes. Gewöhnliche ASCII-Zeichen (A-Z, 0-9) besitzen in UTF-8 dieselben Bytewerte wie im ASCII-Zeichensatz. IBM i unterstützt Unicode seit vielen Jahren. Moderne SQL-Anwendungen, Webservices und Schnittstellen können deshalb UTF-8 einsetzen, ohne dass sämtliche bestehenden EBCDIC-Anwendungen auf einmal umgestellt werden müssen. Gerade darin liegt ein Vorteil: Bewährte RPG-Anwendungen können weiterhin mit EBCDIC arbeiten, während neue Schnittstellen Unicode verwenden.

8. Empfehlungen für die Praxis

Bei bestehenden IBM-i-Anwendungen sollte die Zeichencodierung nicht ohne vorgängiger gewissenhafter Analyse verändert werden. Sinnvolle Massnahmen sind:
  1. System-, Datenbank- und Job-CCSIDs dokumentieren
  2. Textfelder mit CCSID 65535 identifizieren und deren tatsächlichen Inhalt prüfen
  3. Bei externen Schnittstellen die erwartete Zeichencodierung ausdrücklich festlegen
  4. Für neue textbasierte Schnittstellen vorzugsweise UTF-8 verwenden
  5. Konvertierungen mit Umlauten, Akzenten, Eurozeichen und weiteren Sonderzeichen testen
  6. Bestehende Programme auf Annahmen über Bytewerte, Feldlängen und Sortierreihenfolgen untersuchen
Auffinden von Datenbank-Feldern mit CCSID = 65535:
SQL
SELECT                                        
    SUBSTR(TABLE_SCHEMA, 1, 10) LIBRARY,
    SUBSTR(TABLE_NAME, 1, 10) FILE,
    SUBSTR(COLUMN_NAME, 1, 10) FIELD,
    ORDINAL_POSITION POS_IN_FILE,
    DATA_TYPE,
    CCSID
FROM QSYS2.SYSCOLUMNS
WHERE CCSID = 65535
  AND DATA_TYPE IN ('CHAR', 'VARCHAR', 'CLOB')
ORDER BY 1, 2, 4;

9. Fazit

Codepages und CCSIDs gehören zu den Grundlagen von IBM i, die im täglichen Betrieb oft kaum wahrgenommen werden. Solange alle beteiligten Systeme dieselbe Zeichencodierung verwenden oder korrekt konvertieren, funktionieren sie unauffällig. Probleme entstehen vorwiegend beim Datenaustausch, bei Modernisierungen oder beim Zugriff neuer Anwendungen auf ältere Datenbestände. CCSID 65535 ist dabei ein typisches Beispiel: Was im ursprünglichen Umfeld zuverlässig funktionierte, kann bei einer modernen Schnittstelle zum Hindernis werden.
Die entscheidende Erkenntnis: Nicht EBCDIC ist das Problem, sondern die fehlende oder falsche Information darüber, wie gespeicherte Bytes interpretiert werden müssen. IBM i bietet seit Jahrzehnten die technischen Möglichkeiten, unterschiedliche Zeichencodierungen kontrolliert miteinander zu verbinden. Eine saubere Bestandsaufnahme und gezielte Konvertierung sind deshalb oft sinnvoller als eine überstürzte Umstellung bestehender Anwendungen.

Quellen und weiterführende Informationen

IBM Dokumentation, Systemwert QCCSID:
https://www.ibm.com/docs/en/i/7.5?topic=values-coded-character-set-identifier-qccsid-system-value
IBM Support, Data Transfer and CCSID 65535 Database Files:
https://www.ibm.com/support/pages/data-transfer-and-ccsid-65535-database-files
IBM Dokumentation, SQL CAST Specification:
https://www.ibm.com/docs/en/i/7.4.0?topic=expressions-cast-specification