CCSID et pages de codes – Codage des caractères sur IBM i (AS/400)

1. Introduction

Toute personne travaillant sur IBM i rencontre tôt ou tard les notions de page de codes et de CCSID. Généralement lorsque des caractères accentués s'affichent incorrectement, que des caractères spéciaux disparaissent ou que des signes inattendus apparaissent lors d'échanges de données avec Windows, Linux ou d'autres systèmes. La cause réside souvent non pas dans les données elles-mêmes, mais dans leur interprétation.

2. Qu'est-ce qu'une page de codes ?

Un ordinateur ne stocke pas des lettres, mais des valeurs numériques. Une page de codes définit la valeur associée à chaque caractère.
Historiquement, deux familles de codage sont particulièrement importantes :
  • ASCII1 : largement répandu sur les PC et les systèmes Unix
  • EBCDIC2 : traditionnellement utilisé sur les grands systèmes IBM et IBM i
Voici deux exemples :
Caractère            Codage                     Hexadécimal     Décimal
Lettre majuscule A   ASCII                      41              65
                     EBCDIC (page de codes 500) C1              193
                     UTF-8                      41              65
Espace               ASCII                      20              32
                     EBCDIC (page de codes 500) 40              64
                     UTF-8                      20              32
Un texte EBCDIC ne peut donc pas simplement être interprété comme de l'ASCII. Les données doivent être converties de manière appropriée.

3. Qu'est-ce qu'un CCSID ?

CCSID signifie « Coded Character Set Identifier »3
Alors qu'une page de codes décrit la correspondance entre caractères et valeurs numériques, le CCSID définit chez IBM le codage de caractères utilisé, y compris le jeu de caractères et les règles de codage associées. Les pages de codes tiennent également compte des particularités nationales, régionales et linguistiques.
Voici quelques CCSID courants sur IBM i :
CCSID   Signification
37      EBCDIC, États-Unis/Canada
273     EBCDIC, Allemagne
500     EBCDIC, international
1141    EBCDIC, Allemagne avec symbole euro
1208    Unicode UTF-8
13488   Unicode UTF-16
65534   Aucun codage de caractères attribué ; conversion normale (automatique) du texte impossible (*MSG)
65535   Aucun codage de caractères attribué ; conversion normale (automatique) du texte impossible (*HEX)
Le CCSID 65535 est un héritage des anciens systèmes. Ses particularités sont examinées plus loin.

4. Les CCSID sur IBM i

Différents CCSID peuvent coexister sur IBM i, notamment aux niveaux suivants :
- Valeur système      DSPSYSVAL SYSVAL(QCCSID)
- Profil utilisateur  DSPUSRPRF USRPRF(MYUSER) TYPE(*BASIC)
- Travail (job)       DSPJOB OPTION(*DFNA)
- Zone de base        DSPFFD FILE(MYLIB/MYFILE)
- Membre source       DSPFD FILE(MYLIB/QRPGLESRC) TYPE(*ATR)
- Fichiers dans l'IFS DSPATR OBJ('/home/MYLIB/MYFILE.txt')
Au niveau des zones de base de données, ces informations peuvent également être affichées par SQL :
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;
Lors des opérations sur la base de données, IBM i peut convertir automatiquement les données entre différents CCSID, pour autant que leurs codages soient connus et que les caractères puissent être représentés. Cette conversion automatique constitue précisément l'un des atouts de la plateforme.

5. Problèmes courants dans la pratique

CCSID différents

Lorsqu'un programme écrit du texte provenant d'un environnement en CCSID 273 dans une zone de base de données en CCSID 37, IBM i effectue lui-même la conversion nécessaire. En revanche, si un CCSID incorrect est déclaré, certains caractères spéciaux peuvent être altérés.

Échanges de données avec Windows et Linux

Aujourd'hui, le format UTF-8 est souvent attendu pour les fichiers CSV ou les interfaces. Une exportation peut, par exemple, être effectuée ainsi :
CMD
CPYTOIMPF FROMFILE(MYLIB/MYFILE)
          TOSTMF('/home/export.csv')
          STMFCCSID(1208)
          RCDDLM(*CRLF)
Le fichier de sortie est ainsi créé avec le CCSID 1208 (UTF-8). Cela suppose que les zones de texte sources soient correctement déclarées afin de permettre une conversion pertinente.

RPG et SQL

Les programmes RPG et les instructions SQL sont également concernés par les différences de CCSID. En particulier, lorsque des zones EBCDIC, des données Unicode et des interfaces externes sont combinées, il faut connaître le CCSID utilisé par chaque opérande. Un codage incorrect ne se corrige pas simplement en attribuant un autre CCSID. Les données réellement contenues doivent, si nécessaire, être converties.

6. CCSID 65535 – un héritage typique

On rencontre fréquemment le CCSID 65535 dans les anciennes applications AS/400. Il indique qu'aucun codage de caractères précis n'a été attribué aux fichiers, zones ou octets, ce qui empêche la conversion automatique habituelle du texte. Cela ne signifie pas nécessairement que les données stockées sont réellement binaires. Souvent, ces zones contiennent du texte EBCDIC tout à fait ordinaire. La définition ne précise simplement pas selon quelle page de codes ce texte doit être interprété.

Pourquoi utilisait-on 65535 ?

Plusieurs raisons existaient et existent encore :
  • On souhaitait éviter les conversions automatiques de caractères
  • L'application fonctionnait exclusivement dans un environnement EBCDIC homogène
  • Certaines zones contenaient à la fois du texte et des données binaires
  • Les programmes existants devaient continuer à fonctionner sans modification
Tant que les données restent utilisées exclusivement dans leur environnement IBM i habituel, ces inconvénients passent presque inaperçus.

CCSID 65534 et 65535 dans les objets IBM

Le CCSID par défaut des files d'attente de messages, des files d'attente de messages de travail, des listes de réponses système et des journaux historiques est 65534. Cette valeur est également désignée par *MSG ou *MSGD.
Le CCSID par défaut des fichiers de messages est 65535. Cette valeur est également désignée par *HEX.

Où apparaissent les difficultés aujourd'hui ?

Prenons un exemple : un fichier clients contient des noms et des adresses dans une zone alphanumérique dont le CCSID est 65535. En réalité, les octets sont toutefois codés selon la page de codes EBCDIC allemande.
Un ancien programme RPG affiche correctement les noms, car il suppose la même interprétation des octets. Une nouvelle application web lit les données par une interface SQL et attend de l'UTF-8.
Comme la définition de la zone ne fournit aucun CCSID de texte exploitable, la conversion automatique n'a pas lieu. Résultat : des caractères illisibles, des lettres accentuées ou des caractères spéciaux incorrects.4

Comment résoudre le problème ?

La première étape consiste à examiner les octets réellement stockés et le codage utilisé jusqu'alors. Ce n'est qu'ensuite qu'il est possible de déterminer comment interpréter correctement le contenu et, si nécessaire, le convertir vers un nouveau CCSID. Pour les nouvelles interfaces, une conversion ciblée vers UTF-8 est souvent appropriée. Dans les fichiers de base de données existants, il peut être judicieux, à long terme, de définir les zones de texte avec leur CCSID réel. La prudence est toutefois de mise : une simple redéclaration du CCSID ne constitue pas un nettoyage des données. Une modification de la définition des zones ou des octets sous-jacents peut avoir des conséquences sur les programmes RPG, les tris, les comparaisons, les accès aux bases de données et les interfaces. Le CCSID 65535 n'est pas fondamentalement erroné. Il peut être pertinent pour de véritables données binaires ou des octets qui doivent volontairement être transmis sans modification. Pour les zones de texte ordinaires, il constitue en revanche souvent une difficulté majeure.
Pour la valeur système QCCSID, la valeur 65535 mérite une attention particulière : lors d'une modernisation, il convient de vérifier les CCSID réellement utilisés par les travaux et les zones ainsi que les interfaces concernées, plutôt que de modifier sans analyse le paramètre système.

7. Unicode – l'alternative moderne

Unicode définit un jeu de caractères universel couvrant pratiquement tous les caractères couramment utilisés aujourd'hui. Parmi les formes de codage répandues figurent UTF-85 et UTF-166. UTF-8 utilise entre un et quatre octets selon le caractère. Les caractères ASCII ordinaires (A-Z, 0-9) possèdent en UTF-8 les mêmes valeurs d'octets qu'en ASCII. IBM i prend en charge Unicode depuis de nombreuses années. Les applications SQL modernes, les services web et les interfaces peuvent donc utiliser UTF-8 sans qu'il soit nécessaire de migrer simultanément toutes les applications EBCDIC existantes. C'est précisément un avantage : les applications RPG éprouvées peuvent continuer à fonctionner en EBCDIC tandis que les nouvelles interfaces utilisent Unicode.

8. Recommandations pratiques

Dans les applications IBM i existantes, il ne faut pas modifier le codage des caractères sans une analyse préalable approfondie. Les mesures utiles sont les suivantes :
  1. Documenter les CCSID du système, des bases de données et des travaux
  2. Identifier les zones de texte en CCSID 65535 et examiner leur contenu réel
  3. Définir explicitement le codage de caractères attendu pour les interfaces externes
  4. Privilégier UTF-8 pour les nouvelles interfaces textuelles
  5. Tester les conversions avec des caractères accentués, le symbole euro et d'autres caractères spéciaux
  6. Examiner les programmes existants afin d'identifier leurs hypothèses concernant les valeurs d'octets, les longueurs de zones et les ordres de tri
Recherche des zones de base de données avec 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. Conclusion

Les pages de codes et les CCSID font partie des notions fondamentales d'IBM i qui passent souvent inaperçues dans l'exploitation quotidienne. Tant que tous les systèmes concernés utilisent le même codage de caractères ou effectuent correctement les conversions, tout fonctionne sans difficulté apparente. Les problèmes surviennent principalement lors des échanges de données, des modernisations ou de l'accès de nouvelles applications à d'anciennes données. Le CCSID 65535 en est un exemple typique : ce qui fonctionnait de manière fiable dans l'environnement d'origine peut devenir un obstacle pour une interface moderne.
Le constat essentiel est le suivant : le problème n'est pas EBCDIC, mais l'absence d'informations, ou des informations erronées, sur la manière d'interpréter les octets stockés. Depuis des décennies, IBM i offre les moyens techniques de faire communiquer de manière contrôlée différents codages de caractères. Un inventaire rigoureux et une conversion ciblée sont donc souvent préférables à une migration précipitée des applications existantes.

Sources et informations complémentaires

Documentation IBM, valeur système QCCSID :
https://www.ibm.com/docs/fr/i/7.5?topic=faqs-i-system-value-qccsid
Support IBM, Data Transfer and CCSID 65535 Database Files (documentation en anglais) :
https://www.ibm.com/support/pages/data-transfer-and-ccsid-65535-database-files
Documentation IBM, SQL CAST Specification (documentation en anglais) :
https://www.ibm.com/docs/en/i/7.4.0?topic=expressions-cast-specification

Cet article est une traduction de l'original allemand réalisée avec l'aide de l'intelligence artificielle