Le fichier physique (PF), des DDS au SQL
Le PF est la table de l'IBM i. On le crée encore souvent en DDS, un langage en colonnes né avec le System/38 en 1978. Pourquoi les DDS ont été inventées, comment créer un PF, y ajouter, modifier et supprimer des données avec UPDDTA, puis la même table en SQL et ce qui change vraiment, démontré sur un IBM i 7.5.
En une phrase
Un fichier physique (PF, physical file) est l'objet
*FILE qui contient les données d'une table : un format d'enregistrement qui décrit ses
zones, les enregistrements eux-mêmes, et souvent une clé. On le décrit en DDS ou on le
crée en SQL : dans les deux cas, c'est le même type d'objet, lisible par un programme
RPG comme par une requête SQL.
Pourquoi les DDS ont été inventées
En 1978, IBM présente le System/38, ancêtre direct de l'AS/400, avec une base de données intégrée au système. Dans le recueil technique qu'IBM publie la même année, C. D. Truxal et S. R. Ridenour décrivent le problème qu'il fallait régler : jusque-là, chaque programme, chaque utilitaire décrivait lui-même les données qu'il lisait, et ces descriptions différaient souvent. Résultat : des définitions en double, et des programmes incompatibles entre eux.
La réponse du System/38 : une seule description, au niveau de la zone, rangée avec le fichier pour toute sa vie. Les compilateurs la relisent (le programme RPG n'a plus à décrire l'enregistrement : c'est le fichier décrit en externe), les utilitaires s'en servent pour afficher des invites claires, et chaque format porte un niveau : si la description change, un programme compilé avec l'ancienne est signalé. Les fichiers décrits dans le programme restent possibles, surtout pour convertir les applications existantes.
Pourquoi un langage en colonnes ? Dans le même recueil, A. J. Conway et D. G. Harvey expliquent que décrire des fichiers, des zones, des écrans est un travail déclaratif, traditionnellement fait sur des formulaires à colonnes fixes. Plutôt que de l'enfermer dans le CL, langage de commandes, ou dans le RPG, IBM crée un formulaire séparé, à l'image du RPG III de l'époque : la data description specification, les DDS. Elle sert aux fichiers base de données comme aux écrans et aux états imprimés.
Sur l'AS/400, le SQL est proposé par un programme sous licence, SQL/400 (5728-ST1), dont le guide de programmation porte un copyright de 1988. Depuis, les deux façons coexistent et produisent le même type d'objet.
Ce qu'est un PF
- Un objet de type
*FILE, d'attributPF, rangé dans une bibliothèque, qui contient les données. Le fichier logique (LF), lui, n'en contient pas : c'est une vue, un autre ordre ou une sélection sur un ou plusieurs PF. - Un seul format d'enregistrement : la liste des zones, avec leur type et leur longueur.
- Des membres : les enregistrements sont rangés dans un ou plusieurs membres. Le recueil de 1978 cite l'exemple d'un fichier de commandes annuel à douze membres, un par mois. Par défaut, CRTPF n'en permet qu'un (MAXMBRS(1)).
- Un chemin d'accès : par ordre d'arrivée, ou par clé si le PF en déclare une.
- Les fichiers source (QDDSSRC, QRPGLESRC…) sont eux aussi des PF : chaque membre est un source.
Créer un PF en DDS
Sur notre IBM i 7.5, une bibliothèque JOBIPF et un fichier source pour les DDS :
CRTLIB LIB(JOBIPF) TEXT('job-i.fr : demonstration PF')
CRTSRCPF FILE(JOBIPF/QDDSSRC) RCDLEN(92)
Le membre CLIENT, de type PF, saisi par exemple avec SEU (STRSEU) ou dans VS Code avec Code for IBM i :
A* Fichier des clients : un format, une cle unique
A UNIQUE
A R CLIENTR TEXT('Client')
A NUMCLI 5P 0 COLHDG('Numero' 'client')
A TEXT('Numero du client')
A NOM 30A COLHDG('Nom')
A TEXT('Raison sociale')
A VILLE 20A COLHDG('Ville')
A CATEG 1A COLHDG('Cat')
A TEXT('Categorie A, B ou C')
A VALUES('A' 'B' 'C')
A SOLDE 9P 2 COLHDG('Solde')
A EDTCDE(J)
A K NUMCLI
Chaque information a sa colonne :
| Colonnes | Contenu |
|---|---|
| 6 | Type de spécification : A pour les fichiers base de données (facultatif). |
| 7 | Un astérisque fait de la ligne un commentaire. |
| 17 | Type de ligne : R pour le format d'enregistrement, K pour une zone clé, blanc pour une zone. |
| 19 à 28 | Nom du format, de la zone ou de la clé (10 caractères au plus). |
| 30 à 34 | Longueur de la zone. |
| 35 | Type de données : A caractère, P décimal condensé (packed), S décimal étendu (zoned), B binaire, L date, T heure, Z horodatage… |
| 36 et 37 | Nombre de décimales d'une zone numérique. |
| 45 à 80 | Mots-clés : TEXT, COLHDG, VALUES, EDTCDE, et au niveau du fichier UNIQUE. |
Ici : UNIQUE interdit deux clients de même numéro, R CLIENTR nomme le
format, 5P 0 déclare un décimal condensé de 5 chiffres sans décimale, COLHDG
donne l'en-tête de colonne que reprennent les utilitaires, VALUES limite la catégorie à A,
B ou C, et K NUMCLI fait de NUMCLI la clé. Puis on compile :
CRTPF FILE(JOBIPF/CLIENT) SRCFILE(JOBIPF/QDDSSRC)
CPC7301 Fichier CLIENT créé dans la bibliothèque JOBIPF.
CPC7305 Membre CLIENT ajouté au fichier CLIENT de JOBIPF.
CRTPF ajoute aussitôt un membre du même nom. Sans autre précision, le fichier
est créé avec SIZE(10000 1000 3), REUSEDLT(*NO) et MAXMBRS(1),
trois valeurs relevées sur le fichier et qui comptent dans la comparaison avec SQL.
Ajouter, modifier, supprimer avec UPDDTA
UPDDTA crée un programme DFU temporaire, construit à partir de la description du
fichier : pas une ligne de code à écrire. Il s'ouvre en mode MODIFICATION, avec les
en-têtes COLHDG des DDS :
UPDDTA FILE(JOBIPF/CLIENT)

COLHDG des DDS.Ajouter : F10
F10 passe en mode SAISIE. On tape un nouveau client… avec la catégorie « Z », hors
de la liste VALUES. Dans une zone numérique, la touche Fin de zone (Field
Exit) cadre la valeur à droite : 4510 donne 45,10 avec les deux décimales du
format.


VALUES : « Valeur de zone entrée incorrecte ».Corrigée en « B », la saisie est acceptée et l'écran se vide pour le client suivant.
Modifier : F11
F11 revient en mode MODIFICATION : on tape la clé (ici 200, suivie de Fin de zone), Entrée affiche l'enregistrement, on change les zones, Entrée met à jour.

Supprimer : F23, deux fois
Toujours en modification, on affiche le client 900 puis on appuie sur F23 : UPDDTA demande confirmation par un second F23.

F3 termine et affiche le bilan de la séance :

Le programme d'UPDDTA disparaît à la fin de la séance ; pour un programme DFU que l'on conserve et que l'on adapte, on passe par STRDFU.
Voir le contenu, et la place des supprimés
DSPPFM affiche le membre tel qu'il est stocké :

DSPPFM : les zones condensées (numéro, solde) ne sont pas lisibles en clair.Les zones décimales condensées y sont illisibles : DSPPFM montre les octets. Pour lire des valeurs, une requête suffit, car un PF se lit en SQL comme une table :
SELECT * FROM JOBIPF.CLIENT ORDER BY NUMCLI
Les enregistrements supprimés, eux, n'ont pas disparu du disque. Après deux suppressions, le service
QSYS2.SYSPARTITIONSTAT en comptait 2 (NUMBER_DELETED_ROWS) : avec
REUSEDLT(*NO), leur place reste perdue. RGZPFM la récupère :
RGZPFM FILE(JOBIPF/CLIENT)
CPC2983 Données du membre CLIENT réorganisées.
Après la réorganisation : 4 enregistrements, 0 supprimé.
La même table en SQL
CREATE TABLE JOBIPF.CLIENT_EN_SQL FOR SYSTEM NAME CLIENTSQL (
NUMCLI DECIMAL(5, 0) NOT NULL,
NOM CHAR(30) NOT NULL DEFAULT '',
VILLE CHAR(20) NOT NULL DEFAULT '',
CATEG CHAR(1) NOT NULL DEFAULT 'A',
SOLDE DECIMAL(9, 2) NOT NULL DEFAULT 0,
CONSTRAINT JOBIPF.CLIENT_EN_SQL_PK PRIMARY KEY (NUMCLI),
CONSTRAINT JOBIPF.CLIENT_EN_SQL_CATEG CHECK (CATEG IN ('A', 'B', 'C'))
) RCDFMT CLIENTSQLR
Les en-têtes et les textes des DDS deviennent des LABEL ON :
LABEL ON TABLE JOBIPF.CLIENT_EN_SQL IS 'Clients (SQL)';
LABEL ON COLUMN JOBIPF.CLIENT_EN_SQL (
NUMCLI IS 'Numero client', NOM IS 'Nom', VILLE IS 'Ville',
CATEG IS 'Cat', SOLDE IS 'Solde');
LABEL ON COLUMN JOBIPF.CLIENT_EN_SQL (
NUMCLI TEXT IS 'Numero du client', NOM TEXT IS 'Raison sociale',
CATEG TEXT IS 'Categorie A, B ou C');
Deux pièges rencontrés en l'écrivant : FOR SYSTEM NAME est refusé (SQL7029)
quand le nom long est déjà un nom système valide, comme CLIENT_SQL ; et un nom de
contrainte non qualifié se range dans le schéma courant, d'où SQL5051 tant qu'il n'est
pas préfixé par JOBIPF..
Les opérations faites dans UPDDTA s'écrivent ainsi :
INSERT INTO JOBIPF.CLIENT_EN_SQL (NUMCLI, NOM, VILLE, CATEG, SOLDE)
VALUES (500, 'Petit Atelier', 'Lyon', 'B', 45.10);
UPDATE JOBIPF.CLIENT_EN_SQL
SET VILLE = 'Villeurbanne', SOLDE = 150
WHERE NUMCLI = 200;
DELETE FROM JOBIPF.CLIENT_EN_SQL WHERE NUMCLI = 900;
Ces instructions marchent aussi sur le PF créé en DDS : SQL lit et modifie tous les fichiers
physiques. Le service QSYS2.SYSFILES le confirme : les deux objets ont le type natif
PHYSICAL ; seule la table SQL porte en plus le type SQL TABLE.
PF DDS et table SQL : les différences démontrées
| Point | PF créé en DDS | Table créée en SQL |
|---|---|---|
| Définition | Source DDS en colonnes, compilée par CRTPF | Instruction CREATE TABLE |
| Données écrites | Pas vérifiées : un SOLDE fait de blancs est accepté | Vérifiées à l'écriture : CPF5029, rien n'est écrit |
| Valeurs permises | VALUES ne joue qu'à la saisie écran (UPDDTA) ; un INSERT passe | Contrainte CHECK : SQL0545 pour tout le monde |
| Taille | SIZE(10000 1000 3) : 13 000 enregistrements, supprimés compris, puis message à l'opérateur système | Pas de limite fixée (*NOMAX) |
| Enregistrements supprimés | Place perdue jusqu'au RGZPFM (REUSEDLT(*NO)) | Place réutilisée (REUSEDLT(*YES)) |
| Noms | 10 caractères (ALIAS donne un nom long à une zone) | Noms longs pour la table et les colonnes, avec un nom système de 10 caractères |
| Clé | Mot-clé UNIQUE et zone K | Clé primaire (PRIMARY KEY), contraintes nommées |
| Journalisation | Pas automatique : STRJRNPF, ou STRJRNLIB sur la bibliothèque | Automatique si la table est créée dans un schéma SQL (journal QSQJRN) |
1. Les données invalides
C'est la différence qui compte le plus. Nous avons fabriqué un enregistrement brut de 59 octets dont le
SOLDE contient cinq blancs (x'4040404040') au lieu d'un nombre condensé, puis nous l'avons
copié dans les deux fichiers avec CPYF … FMTOPT(*NOCHK) :
Vers le PF DDS : CPC2955 1 enregistrement(s) du membre PLAT copié(s).
Vers la table SQL : CPF5029 (erreur de mappage de données)
CPF2972 Erreur d'écriture dans le membre CLIENTSQL du fichier CLIENTSQL.
La table SQL vérifie les données à l'écriture et refuse. Le PF DDS les accepte, et l'erreur n'apparaît qu'à la lecture, chez le premier qui lit l'enregistrement. Un programme RPG qui parcourt le fichier :
**free
// Lit le PF CLIENT enregistrement par enregistrement et affiche le solde.
ctl-opt dftactgrp(*no) actgrp(*new);
dcl-f client keyed;
read client;
dow not %eof(client);
snd-msg 'Client ' + %char(numcli) + ' : solde ' + %char(solde);
read client;
enddo;
*inlr = *on;
Client 100 : solde 1250.50
Client 200 : solde .00
Client 300 : solde -320.00
MCH1202 Erreur dans une donnée décimale.
RNQ0907 (C G D F) Erreur de données décimales.
Il s'arrête sur le client 400. En SQL, c'est plus sournois : la requête ne s'arrête
pas. Le SOLDE du client 400 revient à NULL, et seul un message d'information
SQL0802 (« Erreur de conversion ou de mappage des données ») reste dans l'historique du
travail, avec CPF5035. Une somme sur tout le fichier, SELECT SUM(SOLDE),
rend elle aussi NULL, sans erreur, alors que quatre soldes sur cinq sont corrects.
2. VALUES n'est pas une contrainte
UPDDTA a refusé la catégorie Z, mais un INSERT SQL dans le même PF DDS l'a acceptée sans broncher.
IBM le précise : les mots-clés de contrôle de validité des DDS (VALUES,
RANGE) ne sont vérifiés que lors d'une saisie sur un écran. La contrainte
CHECK de la table SQL, elle, s'applique à tous :
INSERT INTO JOBIPF.CLIENT VALUES (900, 'Essai categorie', 'Brest', 'Z', 0)
-> accepté
INSERT INTO JOBIPF.CLIENT_EN_SQL VALUES (900, 'Essai categorie', 'Brest', 'Z', 0)
-> SQL0545 INSERT, UPDATE ou MERGE non admis pour une contrainte CHECK.
3. La place des enregistrements supprimés
Sur la table SQL, après une suppression, NUMBER_DELETED_ROWS valait 1 ; l'INSERT suivant
l'a ramené à 0 : la place a été réutilisée, conformément à REUSEDLT(*YES). Sur le PF, il
a fallu RGZPFM.
MCH1202 qu'on rencontre encore sur des fichiers anciens. Pour un nouveau fichier, nous
conseillons donc SQL.
À retenir
- Les DDS (System/38, 1978) donnent une description unique des données, rangée avec le fichier.
- Un PF : un format, des membres, des données ; CRTPF compile la source DDS.
- UPDDTA : F10 saisie, F11 modification, F23 deux fois pour supprimer, Fin de zone dans les zones numériques.
- Une table SQL est aussi un PF, mais elle vérifie les données à l'écriture, applique ses contraintes CHECK et réutilise la place des supprimés.
Sources
Les exemples ont été créés et relevés sur un IBM i 7.5 (voir la méthode). Les définitions et les règles viennent de ces sources, consultées le 16 octobre 2026 :
- IBM System/38 Technical Developments : File and data definition facilities in System/38, IBM, C. D. Truxal et S. R. Ridenour (1978, PDF numérisé). Les descriptions de données redondantes et divergentes d'avant (« each program … has required a separate definition of the data »), la description centrale par les DDS réutilisée par les compilateurs et les utilitaires, le contrôle de niveau, les fichiers décrits dans le programme conservés pour la conversion, les PF à un seul format et leurs membres. Le même recueil contient l'article de Conway et Harvey sur le choix d'un formulaire déclaratif séparé du programme, et l'indépendance des programmes vis-à-vis de la structure physique grâce aux fichiers logiques ; le LF qui fait suivre chaque en-tête de ses lignes de détail.
- IBM Structured Query Language/400 : Programmer's Guide (SC21-9609-1), IBM (1988, 1989, PDF numérisé). Le SQL sur AS/400 sous forme de programme sous licence SQL/400 (5728-ST1), copyright 1988.
- IBM i 7.5 Database : Database programming, IBM (PDF). Fichiers physiques et logiques, membres, REUSEDLT, mots-clés de contrôle de validité (VALUES, RANGE) appliqués seulement à la saisie sur un écran.
- IBM i 7.2 Programming : DDS for physical and logical files, IBM (PDF). Positions de la spécification DDS (17 type de nom, 19 à 28 nom, 30 à 34 longueur, 35 type, 36 et 37 décimales, 45 à 80 mots-clés), mots-clés UNIQUE, TEXT, COLHDG, VALUES, EDTCDE.
- IBM i 7.5 Database : SQL programming, IBM (PDF). Tables SQL créées avec REUSEDLT(*YES), journalisation automatique dans QSQJRN pour une table créée dans un schéma.
- L'aide en ligne des commandes citées, livrée avec IBM i 7.5 et reprise en français dans les fiches des commandes CL de ce site. Paramètres de CRTPF, CRTLF, CRTSRCPF, ADDPFM, OVRDBF, UPDDTA, DSPPFM, RGZPFM, CPYF, CRTBNDRPG et CRTBNDCL.
Questions fréquentes
Qu'est-ce qu'un PF sur IBM i ?
Un fichier physique (physical file) est l'objet *FILE qui contient réellement les données d'une table : un format d'enregistrement (la liste des zones), les enregistrements, rangés dans un ou plusieurs membres, et éventuellement un chemin d'accès par clé. Une table créée en SQL est elle aussi un fichier physique.
Pourquoi IBM a-t-il inventé les DDS ?
Pour le System/38, annoncé en 1978. Auparavant, chaque programme décrivait lui-même les données qu'il lisait, et ces descriptions différaient d'un programme à l'autre. Les DDS donnent une description unique, rangée avec le fichier et réutilisée par les compilateurs, les utilitaires et les commandes, sous la forme d'un formulaire en colonnes, comme le RPG de l'époque.
Comment créer un fichier physique ?
On écrit sa description en DDS dans un membre de type PF d'un fichier source (QDDSSRC), puis on lance CRTPF FILE(bib/fichier) SRCFILE(bib/QDDSSRC). En SQL, CREATE TABLE crée directement le fichier physique.
Comment modifier les données d'un PF sans programme ?
Avec UPDDTA FILE(bib/fichier), qui crée un programme DFU temporaire : F10 pour saisir de nouveaux enregistrements, F11 pour modifier ou supprimer (F23, deux fois) après avoir tapé la clé. En SQL, INSERT, UPDATE et DELETE font la même chose, sur un PF comme sur une table.
Faut-il encore créer ses fichiers en DDS ?
Pour un nouveau fichier, SQL apporte plus de contrôles : données vérifiées à l'écriture, contraintes CHECK, noms longs, pas de limite de taille fixée. Les PF existants décrits en DDS restent pleinement utilisables, en RPG comme en SQL, et il faut savoir les lire.
Pourquoi mes enregistrements supprimés prennent-ils encore de la place ?
Un PF créé par CRTPF ne réutilise pas la place des enregistrements supprimés (REUSEDLT(*NO) par défaut) : elle reste perdue jusqu'à un RGZPFM. Une table créée en SQL réutilise cette place (REUSEDLT(*YES)).