Consulter les informations journalisées avec QSYS2.JOURNALED_OBJECTS
et QSYS2.DISPLAY_JOURNAL
Objectifs :
La journalisation des Tables et Fichiers permet de récupérer les informations relatives aux actions opérées sur ces objets.
Cela peut permettre, par exemple, de savoir quand un enregistrement a été créé, modifié ou supprimé.
Il est également possible d’identifier quelle donnée a été modifiée.
L’IBM i dispose pour cela de fonction SQL très pratiques :
QSYS2.JOURNALED_OBJECTS qui permet de savoir si une table est journalisée et si c’est le cas dans quel journal la table est journalisée.
QSYS2_DISPLAY_JOURNAL qui permet de consulter les informations journalisées
QSYS2.JOURNALED_OBJECTS
Pour savoir si une table ou un fichier physique est journalisé et surtout dans quel journal la table est journalisée, il suffit de requêter la table QSYS2.JOURNALED_OBJECTS de la façon suivante :
SELECT JOURNAL_LIBRARY, JOURNAL_NAME, OBJECT_LIBRARY, OBJECT_NAME, OBJECT_TYPE, FILE_TYPE, JOURNAL_IMAGES, OMIT_JOURNAL_ENTRY
FROM QSYS2.JOURNALED_OBJECTS
WHERE OBJECT_NAME = ‘ma_table‘
AND OBJECT_LIBRARY = ‘ma_bibliotheque‘;
Si la requête aboutit, c’est que la table est journalisée.
Les colonnes JOURNAL_LIBRARY et JOURNAL_NAME contiennent le nom de la bibliothèque et le nom du journal utilisé.
QSYS2.DISPLAY_JOURNAL
La fonction Table QSYS2.DISPLAY_JOURNAL permet de récupérer le contenu d’un journal donné :
SELECT * FROM TABLE (QSYS2.DISPLAY_JOURNAL( ‘ma_bibliotheque‘, ‘mon_journal‘));
Mais surtout elle permet de cibler des informations journalisées en particulier.
Par exemple : pour une table donnée durant un interval de temps défini :
SELECT * FROM TABLE (QSYS2.DISPLAY_JOURNAL( ‘ma_bibliotheque‘, ‘mon_journal‘))
WHERE LEFT(OBJECT, 10) = ‘ma_table‘
AND ENTRY_TIMESTAMP >= ‘2025-09-02-14.00.00.000000’
AND ENTRY_TIMESTAMP <= ‘2025-09-21-14.20.00.000000′;
Voici comment remplacer les codes type d’action les plus courants par des libellés plus explicites :
SELECT ENTRY_TIMESTAMP,
SEQUENCE_NUMBER,
CASE WHEN JOURNAL_ENTRY_TYPE = ‘PT’ THEN ‘INSERT’
WHEN JOURNAL_ENTRY_TYPE = ‘PX’ THEN ‘INSERT BY RRN’
WHEN JOURNAL_ENTRY_TYPE = ‘UB’ THEN ‘UPDATE BEFORE’
WHEN JOURNAL_ENTRY_TYPE = ‘UP’ THEN ‘UPDATE AFTER’
WHEN JOURNAL_ENTRY_TYPE = ‘DL’ THEN ‘DELETE’
ELSE JOURNAL_ENTRY_TYPE
END AS JRNTYPE,
LEFT(OBJECT,10) AS JRN_OBJECT,
SUBSTR(OBJECT, 11, 10) AS JRN_OBJECT_LIBRARY,
JOURNAL_IDENTIFIER,
ENTRY_DATA
FROM TABLE (QSYS2.DISPLAY_JOURNAL( ‘ma_bibibliotheque‘, ‘mon_journal‘))
WHERE LEFT(OBJECT, 10) = ‘ma_table‘;
La liste des types d’entrée est disponible ici : All journal entries by code and type – IBM Documentation
La colonne ENTRY_DATA contient les données de l’enregistrement inséré, supprimé ou modifié dans la table.
Mais il faut la convertir pour pouvoir l’expoiter correctement…
Exemple de conversion des données de la colonne ENTRY_DATA
Modification des données d’un enregistrement d’une table journalisée :
UPDATE ma_bibliotheque.ma_table SET PAYS = ‘FRANCE’ WHERE PAYS = ‘FRANC’;
Récupération des ENTRY_DATA avant et après modification :
SELECT
CASE WHEN JOURNAL_ENTRY_TYPE = ‘UB’ THEN ‘UPDATE BEFORE’
WHEN JOURNAL_ENTRY_TYPE = ‘UP’ THEN ‘UPDATE AFTER’
ELSE JOURNAL_ENTRY_TYPE
END AS JRNTYPE,
ENTRY_DATA
FROM TABLE (QSYS2.DISPLAY_JOURNAL( ‘ma_bibliotheque‘, ‘mon_journal‘))
WHERE LEFT(OBJECT, 10) = ‘ma_table‘
AND JOURNAL_ENTRY_TYPE IN(‘UB’, ‘UP’);
Résultat :
Les ENTRY_DATA retournés sont difficilement exploitables.
Récupération de la longueur des enregistrements de la table journalisée :
SELECT MAXIMUM_RECORD_LENGTH
FROM QSYS2.SYSFILES
WHERE LIB_NAME = ‘ma_bibliotheque‘
AND TABLE_NAME= ‘ma_table‘;
Retourne 183 par exemple.
Conversion des 183 caractères en une seule fois :
SELECT
CASE WHEN JOURNAL_ENTRY_TYPE = ‘UB’ THEN ‘UPDATE BEFORE’
WHEN JOURNAL_ENTRY_TYPE = ‘UP’ THEN ‘UPDATE AFTER’
ELSE JOURNAL_ENTRY_TYPE
END AS JRNTYPE,
INTERPRET(CAST(SUBSTRING(ENTRY_DATA, 1, 183) AS CHAR(183)) AS CHAR(183)) AS INTERPRET_ENTRY_DATA
FROM TABLE (QSYS2.DISPLAY_JOURNAL( ‘ma_bibliotheque‘, ‘mon_journal‘))
WHERE LEFT(OBJECT, 10) = ‘ma_table‘
AND JOURNAL_ENTRY_TYPE IN(‘UB’, ‘UP’);
Résultat :
Les caractères ont bien été convertis.
C’est suffisant pour voir que ‘FRANC’ a été modifié en FRANCE’.
Mais les données numérique ne sont pas lisibles.
Il va donc découper les données de la colonne ENTRY_DATA en différentes parties, chacune de ces parties correspondant à un champ de la table journalisée, puis convertir chacune de ces parties pour pouvoir obtenir un résultat totalement lisible et exploitable.
On récupère la définition et surtout la longueur de stockage de chaque champ de la table journalisée avec la requête suivante :
SELECT COLUMN_NAME, DATA_TYPE, LENGTH, NUMERIC_SCALE, STORAGE, NUMERIC_PRECISION
FROM QSYS2.SYSCOLUMNS
WHERE SYSTEM_TABLE_NAME = ‘ma_table’
AND SYSTEM_TABLE_SCHEMA = ‘ma_bibliotheque’;
Résultat :
Puis on convertit les champs qui nous intéressent en fonction de leurs positions, leurs types et de leurs longueurs de stockage :
SELECT
CASE WHEN JOURNAL_ENTRY_TYPE = ‘UB’ THEN ‘UPDATE BEFORE’
WHEN JOURNAL_ENTRY_TYPE = ‘UP’ THEN ‘UPDATE AFTER’
ELSE JOURNAL_ENTRY_TYPE
END AS JRNTYPE,
INTERPRET(CAST(SUBSTRING(ENTRY_DATA, 1, 20) AS CHAR(20)) AS CHAR(20)) AS PAYS,
INTERPRET(CAST(SUBSTRING(ENTRY_DATA, 21, 20) AS CHAR(20)) AS CHAR(20)) AS CONTINENT,
INTERPRET(CAST(SUBSTRING(ENTRY_DATA, 41, 2) AS CHAR(2)) AS DEC(2,0)) AS NB_COUPES,
INTERPRET(CAST(SUBSTRING(ENTRY_DATA, 43, 3) AS CHAR(3)) AS DEC(4,0)) AS ANNEE_1,
INTERPRET(CAST(SUBSTRING(ENTRY_DATA, 46, 20) AS CHAR(20)) AS CHAR(20)) AS ORGANISATEUR_1,
CAST(INTERPRET(CAST(SUBSTRING(ENTRY_DATA, 158, 26) AS CHAR(26)) AS CHAR(26)) AS TIMESTAMP) AS TS_MAJ
FROM TABLE (QSYS2.DISPLAY_JOURNAL( ‘ma_bibliotheque‘, ‘mon_journal‘))
WHERE LEFT(OBJECT, 10) = ‘ma_table‘
AND JOURNAL_ENTRY_TYPE IN(‘UB’, ‘UP’);
Résultat :
Après découpage et conversion, on voit que le ‘FRANC’ a été remplacé par ‘FRANCE’ et que le timestamp de modification de l’enregistrement a été mis à jour également.