QEZJOBLOG et QEZDEBUG

Vous avez 2 files de sortie dans QUSRSYS (OUTQ) QEZJOGLOG et QEZDEBUG

La première QEZJOBLOG correspond au log de vos travaux

Rappel un travail va produire une log en fonction des paramètres indiqués, LOG() et LOGCLPGM() du travail

Par défaut ces spools sont placés dans la file QEZJOBLOG, si ce n’est pas le cas voici comment corriger et revenir à un schéma habituel.

Ce paramétrage est sur le fichier PRTF, QPJOBLOG que vous pouvez modifier par CHGPRTF

La deuxième correspond aux dumps générés dans les travaux

pour rapple , un dump c’est un vidage mémoire des variables au moment du plantage dans un programme

Vous les obtenez soit de manière automatique, soit en répondant ‘D’ sur un message en attente

Par défaut ces spools sont placés dans la file QEZDEBUG, si ce n’est pas le cas voici comment corriger et revernir à un schéma habituel

Ce paramétrage est sur le fichier prtf QPPGMDMP que vous pouvez modifier par CHGPRTF

Vous avez toujours intérêt à répondre D sur un message plutôt que C , vous aurez ce spool qui pourra vous aidez à comprendre le problème

Remarque :

pour le ménage vous avez le cleanup qui va gérer la rétention dans ces 2 files

==> Go Cleanup

Choisir option 1

par défaut vous garderez 30 jours

Merci à Betty pour le test

Changement de machine : retour d’expérience

Un de nos clients a décidé de passer son infrastructure informatique sur le cloud.

Rien à redire à cela, derrière ce sont toujours des Powers qui répondront aux requêtes. Par contre cela a permis de faire quelques tests de performances avec des résultats étonnants.

Le client est passé d’une partition S824 à une partition S922.

  • Même capacité mémoire,
  • même capacité disque,
  • même fraction processeur.

Seul le processeur a changé : passage d’un P8 S824 à un P9 S922.

L’application test consistait en une chaine de 160 programmes RPGLE, SQLRPGLE, 30 programmes CLLE, 80 PF multi-formats et tables SQL en sortie et une vingtaine de PF en entrée.

L’application contient des accès natifs à la base de données, des requêtes SQL…

mais n’est pas en écriture modulaire, pas de programmes de services, de répertoire de liage, de groupes d’activation dédiés,…

Selon le paramétrage, on accède soit à 10 millions d’enregistrements en entrée (V10) soit à plus de 200 millions d’enregistrements en entrée (V200) donc 20 fois plus.

Cette application a été utilisée par le passé sur des P7 (724), P8 (824) avec à chaque fois des gains dans les temps d’exécution.

L’opération est simple : changement de machine et passage à une gamme processeur plus récent, MAIS passage d’un S824 à un S922.

Données de référence :Sur un P8/S824 la V10 dure 21 minutes. (moyenne sur 7 mois avec plusieurs lancés sur le même mois et des valeurs de temps entre 20 et 22 minutes).

Sur un P8/824 la V200 dure 7 heures (420 minutes, la règles de proportionnalité nous donne 420/20 : 21

Compte tenu de la durée des traitements, seule la V10 a été lancée pour valider les gains de temps.

Tests avec même fraction processeur (0.3), même mémoire, même capacité disque MAIS passage de disques de 133 Go à des disque de 260 Go.

– Temps moyen S922 : 41 minutes. (3 tests avec l’application seule sur la machine, temps identique à +/- 1 minute)

Test avec fraction processeur à 1, mémoire principale multipliée par 4 :

– Temps moyen S922 : 40 minutes. (3 tests avec l’application seule sur la machine, temps identique à +/- 1 minute)

Test avec multiplication du nombre de contrôleurs disque par 3 :

– Temps moyen inchangé

Test remplacement des disques de 260 Go par des disques de 133 Go :

– Temps moyen inchangé

D’après vous quel était l’élément pénalisant ?

Le processeur. Ou plutôt, la vitesse d’horloge de celui-ci.

Sur le S824, le processeur était cadencé à 4.15 Ghz.

Sur le S922, le processeur était cadencé à 2.275 GHz.

Sur un traitement interactif, cette donnée est négligeable et la différence de temps insignifiante.

Par contre sur du batch, le résultat peut être catastrophique.

Si on reporte sur le traitement V200 les résultats du V10, on obtient une durée qui passe de 7h à plus de 13h !

Heureusement (ou presque) en passant la fréquence à 3.9 GHz le temps moyen s’est amélioré :

– Temps moyen : 25 minutes.

Aucun gain mais moins de pertes.

Conclusion : Il faut toujours faire attention aux petits détails lors des changements de machine.

, Fréquence des IPL, complément

Fréquences des IPL, complément

La precaunistation d’IBM et de faire IPL à chaque appliction de PTFs
pour ne pas perdre le chache SQL par exemple

Mais, il y a quand même un point inviter à en faire plus, c’est la mémoire qui est perdu sur certain travaux

Vous avez une vue QSYS2.SYSTMPSTG qui permet

La vue SYSTMPSTG contient une ligne pour chaque espace de stockage temporaire qui contient une quantité de stockage temporaire sur le système.
Le stockage temporaire est un stockage qui ne persiste pas lors d’un redémarrage du système d’exploitation.
on parle de « BUCKET »

Voici une requête qui montre l’espace perdu par les jobs terminés

SELECT ‘Perdu’ as memoire , sum(BUCKET_CURRENT_SIZE) as taille
FROM qsys2.SYSTMPSTG
WHERE JOB_STATUS = ‘*ENDED’

le détail

SELECT JOB_NAME, JOB_USER_NAME, JOB_NUMBER , BUCKET_CURRENT_SIZE
FROM qsys2.SYSTMPSTG
WHERE JOB_STATUS = ‘*ENDED’
order by BUCKET_CURRENT_SIZE desc

Voici une requête qui donne la taille totale

SELECT ‘Total’ as memoire , sum(BUCKET_CURRENT_SIZE) as taille
FROM qsys2.SYSTMPSTG ;

Vous pouvez faire un ratio et si il est important 10 % par exemple

Vous devrez faire une IPL, pour récupérer cette mémoire

Vue dans Navigator For I

Ps:
A ce jour il n’y a pas d’autres solutions pour récupérer cette mémoire

, Démystification de la Modernisation IBMi

Cette semaine c’est un article un peu spéciale c’est notre ami Jérôme Clément qui nous livre ses réflexions éclairées sur la modernisation de vos applications #ibmi et ses enjeux , merci à lui pour ce partage .

Objectifs

Cet article a pour objectif de démystifier la modernisation IBMi et surtout de mettre en évidence toutes les actions de modernisation réalisables aisément qui faciliteront grandement les actions d’envergure qui seront à réaliser ensuite.

Le concept de Modernisation de l’IBMi est, certes, très vaste et peut paraitre très difficile à mettre en œuvre mais nous allons voir que cette modernisation repose aussi sur de nombreuses étapes qui peuvent, elles, être réalisées facilement et rapidement par les équipes internes à l’entreprise.

En plus d’être indispensables à la modernisation, ces étapes apporteront une meilleure maîtrise des applicatifs IBMi existants, ce sont des prérequis aux chantiers plus conséquents que sont, par exemple :

  • La mise en place de solutions DEVOPS
  • La conversion automatisée des bases DB2 en bases SQL
  • La transformation des programmes RPG en programmes FREEFORM

Voici quelles sont ces différentes étapes, que je détaillerai ensuite :

  • Adhésion à la démarche
  • Normalisation des développements
  • Définition des bonnes pratiques
  • Documentation et centralisation de la documentation
  • Etat des lieux des applicatifs
  • Modularisation et utilisation des programmes de service
  • Migration progressive d’une base de données DB2 vers une base de données SQL
  • Accès aux données avec SQL
  • Implication des équipes de développement

Adhésion à la démarche

Il est primordial que la démarche de modernisation soit partagée par tous. C’est-à-dire :

  • Par la direction de votre entreprise
  • Par la DSI
  • Par les équipes de développement

Pour être efficace, cette démarche doit être comprise de tous et avoir l’adhésion de chacun.

Cela car elle nécessite des moyens (essentiellement du temps), de la rigueur et l’implication de tous les acteurs.

Il est important que la direction de votre entreprise ait conscience que :

  • La modernisation est nécessaire au bon fonctionnement et aux évolutions futures des applications qui reposent sur l’IBMi.
  • L’IBMi est une machine moderne, en phase avec son époque, capable de s’interfacer avec tous les autres systèmes actuels. Robuste, rapide, économique l’IBMi porte actuellement le cœur de l’activité de votre entreprise, il est primordial de maintenir ce système à niveau.
    La dette technique accumulée au fil des années peut être « remboursée », et cela doit être fait pour pouvoir profiter encore longtemps des investissements déjà réalisés dans la mise en place des applications spécifiques à votre entreprise et spécifiques à votre activité.
  • Quitter l’IBMi pour un autre système peut être une solution. Mais c’est une opération longue, couteuse et risquée. C’est une solution sur laquelle de nombreuses entreprises se sont déjà « cassés les dents ».
  • Il est, selon moi, nettement plus judicieux et beaucoup plus économique de capitaliser sur vos acquis en modernisant vos applicatifs plutôt que de chercher à les remplacer à l’identique ou presque sur un autre support.
  • Moderniser les applicatifs IBMi est un investissement qui ne pourra être mener à bien que s’il est appuyé par la direction de l’entreprise et uniquement si celle-ci donne les moyens à ses équipes de se lancer pleinement dans cette démarche.

Il est important que la DSI ait conscience que :

  • La modernisation nécessite du temps et qu’il va donc falloir en accorder à ses équipes pour la mettre en œuvre.
    En effet, une équipe sous pression d’échéances de livraison de projets ne prendra pas le temps de faire « bien », elle se contentera de faire « vite ». Elle vivra la démarche de modernisation comme une contrainte lui demandant du temps dont elle ne dispose déjà pas. Elle ne percevra pas cette démarche comme un investissement, et cherchera à s’y soustraire à la moindre occasion plutôt que de la porter.
  • La modernisation réduira les coûts des développement futurs.
    La maitrise et la connaissance des applicatifs, la mise en place de services évitant la redondance de code, l’homogénéisation des méthodes de développements, la suppression des programmes obsolètes : toutes ces étapes, une fois réalisées, permettront de gagner du temps dans la réalisation de vos projets.
    Le temps nécessaire à la modernisation sera donc récupéré par la suite. 
  • Certains développeurs peuvent aussi se montrer réfractaires à l’idée de sortir de leur zone de confort en devant changer leurs habitudes de développement. C’est pourquoi la démarche de modernisation doit être portée par la DSI. Il va falloir contrôler que tous les développeurs y participent et la mettent en œuvre. En effet, il est contreproductif de résorber la dette technique d’un côté si c’est pour continuer à la générer d’un autre.

Il est important que les développeurs aient conscience que :

  • La modernisation est nécessaire et qu’elle pérennise la présence de l’IBMi au cœur de l’infrastructure technique de l’entreprise et par conséquent leur présence en tant que développeurs spécialisés sur ce système au sein de l’entreprise.
  • La modernisation est formatrice et donc très positive.

Cette démarche va probablement changer les habitudes des développeurs. Mais il est, me semble-t-il, particulièrement motivant d’avoir à appréhender de nouvelles façons de développer lorsque celles-ci sont plus efficaces et plus performantes. Les développeurs ont tout à gagner à se mettre au RPG FREEFORM, à utiliser au mieux SQL, à développer des programmes de services. C’est un plus pour l’entreprise mais également un plus personnel pour chaque d’entre eux.

Ce qui a pour conséquence une grande disparité dans la façon de nommer les objets comme dans la façon d’écrire les programmes.

Normalisation des développements


Avec les années, le turnover des développeurs internes et les interventions de prestataires externes, on constate bien souvent que chacun a laissé son empreinte, son style, sa façon de développer dans les applicatifs de l’entreprise.

C’est une lapalissade mais il faut normaliser tout ça.

Mettre en place des normes de développement a pour objectifs :

  • De rendre le code homogène afin qu’il soit facilement appréhendable par chaque membre vos équipes.
  • D’identifier facilement les différents objets qui composent vos applications.

Définissez, ensemble, avec tous les membres de vos équipes :

  • Les normes de nommage des objets.
  • Les normes de codification à utiliser dans les sources de vos programmes.

Rédiger un document récapitulatif clair, consultable par chaque membre de vos équipes. Ce document doit devenir une référence, il devra être mis à disposition de chaque nouvelle personne qui rejoindra vos équipes (en interne comme en prestation). Il contribuera à sa bonne intégration et facilitera le respect et la mise en œuvre de ces normes par les nouveaux arrivants.

Définition des Bonnes Pratiques

Là aussi c’est une lapalissade mais c’est très important.

Définissez ces bonnes pratiques, ensemble, en restant à l’écoute des uns et des autres mais en finalisant la réflexion en statuant ces règles dans un document de référence (comme pour les normes de développement).

Et surtout veillez à ce ces bonnes pratiques soient respectées, quitte à développer, si nécessaire, des process de contrôle qui bloqueraient chaque mise en production ne respectant pas les préconisations établies.

Voici quelques exemples de règles de bonnes pratiques classiques dans le cadre de la modernisation :

  • Respecter les normes de développement et les bonnes pratiques définies.
  • Ecrire les nouveaux programmes en RGP FREEFORM.
  • Proscrire les SELECT * dans le SQL EMBEDDED.
  • Gérer les accès à la base de données par SQL.
  • Ne pas créer de nouveaux fichiers physiques ou logiquesDB2, mais créer des tables, index et vues SQL.
  • Convertir chaque programme RPG modifié en programmes RPGLE.
  • Commenter les sources de façon claires et réfléchies en évitant les commentaires inutiles.
  • Utiliser des noms de variables parlant.
  • Ne jamais faire d’accès aux index dans les requêtes SQL, laisser SQL choisir ses modes d’accès aux données.

Documentation et Centralisation des documents

Là aussi, cela semble évident, mais nombre d’entreprise ne documentent pas leurs traitements et s’étonnent ensuite de ne pas maîtriser leurs propres applications.

On constate fréquemment que chaque développeur s’est construit sa propre petite documentation, détaillant telle ou telle chaine de traitement, mais que ces documents ne sont ni partagés, ni à jour.

Il faut donc impérativement :

  • Documenter vos applications.
    Cela peut se mettre en place progressivement, en profitant de chaque nouveau projet, de chaque nouveau développement pour mettre en place cette documentation.
  • Définir des modèles de document qui seront utilisables par tous.
    Cela facilitera la création des documentations suivantes.
  • Centraliser ces documents.
    Pour que chacun puisse y accéder, que chacun puisse y ajouter sa contribution mais surtout pour que toute personne sache où rechercher ces informations.
  • Faire vivre ces documents en les maintenant à jour.

Etat des lieux de vos applicatifs

Faire un état des lieux des applications qui tournent sur l’IBMi permet de quantifier la dette technique à résorber.

Les services SQL permettent en quelques requêtes d’obtenir de très nombreuses informations sur les objets de vos applications.

Elles permettent par exemple :

  • D’identifier les programmes qui n’ont pas été exécutés depuis des années.
    Ces programmes alourdissent vos développements alors qu’ils ne servent plus.
    En effet, chaque analyse d’impact, chaque modification de base de données les prennent en compte ce qui augmente inutilement la charge de travail.
    Identifier ces programmes permet de les sauvegarder leurs sources puis de les supprimer.
    C’est autant de programme qui ne seront plus à moderniser.
  • Contrôler l’unicité des sources des programmes, de façon à n’avoir qu’un seul référentiel de sources. Avoir différentes versions de sources d’un même programme dans différentes bibliothèques est très dangereux. Les développeurs ne doivent pas avoir à s’interroger pour savoir quel est le source à modifier pour ne pas risquer d’écraser les modifications précédemment livrées en production.
  • Vérifier la cohérence entre vos objets de production et votre référentiel de source.
    Il est impératif de pouvoir avoir une totale confiance en son référentiel de source.
    Avoir des objets de production qui ne correspondent pas aux sources du référentiel est très inquiétant. Il faut profiter de la modernisation pour vérifier et remettre la situation à plat.
  • Vérifier et optimiser les requêtes SQL, identifier les plus consommatrices, vérifier et éventuellement créer les index proposés.
  • Mettre en évidence les ratios suivants :
    • Nombre de fichiers DB2 / Nombre de tables SQL
    • Nombre de programme RPG / nombre de programmes RPGLE
  • Identifier le nombre de procédures de services mises en place.

Encapsuler ces requêtes dans des programmes de façon à pouvoir les relancer régulièrement et stocker les résultats obtenus est une idée intéressante.

Cela permettra de mettre en place des métriques pouvant être remontés à la direction pour montrer que le process de modernisation est en œuvre et progresse régulièrement.

Modularisation et utilisation des programmes de service

Convertir les programmes en RPG en RPGLE : c’est bien.

Mais appréhender et mettre en place le concept de programmes de service : c’est mieux.

L’idée qui se cache derrière ce concept est de développer de petits programmes de service, facilement maintenables puisque répondant chacun à une et une seule fonctionnalité bien spécifique. Ces services pourront être ensuite consommés, à chaque instant, par les différents traitements.

Cela permet :

  • D’éviter le code redondant. Puisque le code de la fonctionnalité n’est présent que dans le service et non plus dans chaque chaine de traitement qui utilise sa fonction.
  • De gagner énormément de temps en maintenance puisque seul le service est à modifier en cas d’évolution de la fonctionnalité concernée.
  • De gagner en performance grâce aux groupes d’activation.
    En effet les groupes d’activation permettent de garder en mémoire le service précédemment appelé au sein du même groupe d’activation. Contrairement à un appel de programme classique qui va être monté en mémoire puis déchargé à chaque appel.
  • D’exposer, si nécessaire, ces programmes de services très simplement grâce au serveur intégré à l’IBMi via IWS (websphère), les rendant ainsi également accessibles à des applicatifs hors IBMi.

Ces programmes de services, une fois développés, doivent pouvoir être réutilisés par tous et il ne faut pas qu’une même fonctionnalité face l’objet de plusieurs programmes de service, c’est l’opposé du but recherché.
Pour cela, il est fortement conseillé de mettre en place un dictionnaire de service permettant de :

  • Rechercher les services et les procédures exportées :
    • par leur nom
    • par leur fonction
    • par les tables mise à contribution
  • D’identifier les paramètres en entrée et en sortie de chaque procédure exportée.

En indiquant leur rôle et leur format.

  • De visualiser quelles tables sont utilisées par chaque procédure exportée.

Ceci permettra aux développeurs de trouver facilement le service qui répondra à leur besoin et évitera qu’une même fonctionnalité fasse l’objet de plusieurs services.

Migration progressive d’une base de données DB2 à une base de données SQL

Sans rentrer dés à présent dans le processus de conversion massive de toute la base de données DB2 en base SQL, il est possible de commencer à se dire que toute nouvelle création d’élément de la base de données se fera en SQL.
Ceci en remplaçant les créations de fichiers physiques ou logiques DB2, par des créations de tables, index ou vues SQL.

Ceci permettra de commencer progressivement la bascule de la base de données vers SQL, tout en permettant aux équipes à s’habituer à ce nouveau process.

Accès aux données avec SQL

Cette étape est un peu particulière car il ne s’agit pas juste de dire : il faut faire du SQL EMBEDDED. C’est-à-dire qu’accéder aux données, dans les programmes RPG, par SQL c’est une chose, mais il faut le faire bien.

En effet, cela ne consiste pas simplement à remplacer un CHAIN classique par un SELECT SQL. Cela va bien au-delà de ça.

Par exemple :

Utiliser un CURSEUR SQL, faire une boucle de lecture du curseur, pour ensuite faire différents SELECT à partir des données de chaque enregistrement lu dans le curseur est un non-sens.
Le programme va effectivement accéder aux données par SQL mais sans profiter de la puissance offerte par SQL et les temps de réponses seront donc quasiment similaires à ceux obtenus par un accès « classique » à la base de données.
Alors que si le curseur est fait à partir d’une requête unique comportant des jointures sur les tables lues par les différents SELECT évoqués précédemment ; alors il est plus que probable qu’il y aura un gain de performance significatif.

Outre les gains de performance, SQL apporte également de nombreuses fonctions qui faciliteront les développements.

SQL est un langage qui évolue constamment, et c’est également le cas sur l’IBMi.

De nouvelles fonctions font leur apparition régulièrement.

Et ces fonctions permettent par exemple :

  • De générer un fichier XML en quelques lignes
  • De lire et intégrer un fichier JSON en une seule requête
  • D’envoyer un mail avec le résultat de la requête sous forme de fichier Excel très simplement

Ce ne sont que quelques exemples parmi tant d’autres…

Il est aujourd’hui inconcevable de se passer de SQL même et surtout en tant que développeur IBMi.

Vos équipes auront peut-être, selon leur niveau, besoin de formations avancées sur SQL mais il est indispensable qu’elles sachent utiliser à bon escient les jointures, les tables temporaires, les fonctions SQL afin qu’elles puissent mettre en place des requêtes optimisées, performantes et maintenables facilement dans leurs programmes.

Sans quoi les gains en performance seront restreints alors qu’ils peuvent être tellement importants lorsque les requêtes tirent pleinement profit des possibilités offertes par SQL.

C’est pourquoi, il faudra également présenter aux équipes de développement les outils d’optimisation SQL mis à disposition sous ACS tels que :

  • Visual Explain
  • SQL Performance Center
  • Le Conseil à la création d’index

Implication des équipes de développement

Ces étapes de modernisation sont réalisées par les équipes de développements.
Nous l’avons vu, elles vont avoir besoin de temps pour les mettre en œuvre, mais pas seulement. Il va falloir, si nécessaire, les impliquer en les faisant monter en compétence.

Ceci en :

  • Les formant au RPG FREEFORM si elles ne le connaissent pas déjà
  • Les formant aux concepts des programmes de services
  • Les formant au SQL avancé
  • Les incitant à assister aux événement IBMi qui sont si riches, si formateurs et desquels elles retiendront de nombreuses nouveautés à mettre en pratique.

La démarche de modernisation peut être perçue comme une contrainte mais si c’est le cas c’est que :

  • soit elle a été mal introduite,
  • soit les développeurs n’ont pas les moyens (le temps toujours le temps) de les mettre en pratique et d’en tirer profit.

Si on lui laisse la possibilité de profiter de la modernisation pour monter en compétence, il n’y a aucune raison pour qu’un développeur perçoive la démarche comme une contrainte et n’y adhère pas. Ou alors il est totalement réfractaire au changement mais ça c’est une autre histoire… 

Pour conclure

Ces premières actions ne règleront pas tout, il vous faudra certainement vous outiller ou faire appel à des spécialistes pour répondre à la mise en place du DEVOPS, pour convertir de façon automatique tous vos sources RPG/RPGLE en FREEFORM et pour transformer toutes vos bases DB2 en bases SQL. C’est un fait.

Mais ces actions sont, elles, à la portée de tous et constituent un grand pas dans la démarche de modernisation.

Je détaillerai dans de futures publications comment réaliser telles ou telles étapes abordées de façon synthétique dans ce premier post.

N’hésitez pas à me faire part de vos remarques et/ou de vos questions, je me ferai un plaisir d’y répondre.

Je remercie, encore une fois Pierre-Louis BERTHOIN et Nathanaël BONNET pour la tribune qu’ils m’ont offerte.

J’espère que cet article vous a intéressé et qu’il apportera sa contribution à vos différents projets de modernisation.

Je vous remercie et vous dit à bientôt…

Contrôler la taille des résultats de QUERY400

Vous utilisez encore les QUERY/400 et vous souhaitez contrôler la taille du fichier en sortie ? Cette astuce peut vous être utile.

Lorsque vous choisissez en type de sortie un fichier base de données, par défaut, le fichier est taillé en *NOMAX. Il peut arriver qu’avec une mauvaise jointure que l’on atteigne le million d’enregistrements (voir le milliard). Si vous souhaitez limiter la taille de ce fichier en sortie, il vous suffit de créer une DTAARA dans QGPL avec comme nom QQUPRFOPTS puis de définir le nombre d’enregistrements maximum.

Création de la DTAARA :

CRTDTAARA DTAARA(QGPL/QQUPRFOPTS) TYPE(*CHAR) LEN(80)
             TEXT('Query/400 Options') AUT(*USE)    

Définition de la taille :

Dans l’exemple suivant, je choisis de limiter à 10000 enregistrements et de faire 3 incréments de 1000.

CHGDTAARA DTAARA(QGPL/QQUPRFOPTS (56 20))   
   VALUE('     10000 1000   3 ')

A l’exécution du QUERY, j’aurai le message suivant si je dépasse les 13 000 enregistrements :

Message dans QSYSOPR :

L’administrateur pourra donc décider d’augmenter la taille et/ou appeler l’utilisateur pour savoir s’il ne s’est pas trompé dans sa jointure.

Si jamais vous voulez supprimer le blocage temporairement pour un besoin ponctuel, vous pouvez mettre la DTAARA à blanc.

CHGDTAARA DTAARA(QGPL/QQUPRFOPTS *ALL) VALUE(' ')   

, Mettre des contrôles dans un DSPF

Sur un formulaire de saisie, on va différencier 3 type de contrôles

1) de valeur

exemple doit contenir 1, 2, 3

2) de cohérence

exemple date de fin > date de debut

3) applicatifs

qui nécessite un accès à une ressource externe

exemple

controler que le client existe

Sur une application de type web, on a un formulaire de saisie et les contrôles 1 et 2 sont faits par javascript
et la partie 3 est faite applicativement

Si on considère maintenant un applicatif 5250, on peut faire une grande partie des contrôles 1 directement dans l’écran ,
la partie 2 et 3 seront faites applicativement

Nous allons prendre un DSPF et faire des controles directement dedans

l’écran DSPF


     A*%%TS  SD  20241104  105842  PLB         REL-V7R4M0  5770-WDS
     A*%%EC
     A                                      DSPSIZ(24 80 *DS3)
     A                                      CA03(03)
     A          R FMT01
     A*%%TS  SD  20241104  105842  PLB         REL-V7R4M0  5770-WDS
     A                                  4 29'Ecran de saisie'
     A                                  8 15'Code   :'
     A            CODE           4A  B  8 24DSPATR(MDT)
     A N45                                  DFTVAL('001')
     A                                      CHECK(MF)
     A                                      RANGE('0001' '9999')
     A                                  8 30'Zone remplie obligatoire'
     A                                 11 15'Nom    :'
     A            NOM           30A  B 11 24CHECK(LC)
     A                                      DSPATR(MDT)
     A                                      COMP(NE ' ')
     A                                 12 30'Zone obligatoire '
     A                                 13 30'Minuscules autorisées'
     A                                 15 15'Option :'
     A            OPTION         1N  B 15 24VALUES('1' '2' '4')
     A N45                                  DFTVAL('2')
     A                                 15 30'1 Créer'
     A                                 16 30'2 Modifier'
     A                                 17 30'4 Supprimer'
     A                                 22  5'F3=Exit'
     A                                  9 30'Chiffre uniquement'

Nous allons contrôler que
la zone CODE est remplie
la zone NOM n’est pas vide
la zone OPTION doit prendre comme valeur 1, 2 et 4

On dispose des contrôles
de saisie souvent des CHECK
de validité, COMP, RANGE, VALUE

Pour que le contrôle soit déclenché, la zone devra être modifiée ou on forcera le DSPATR(MDT), pour faire comme si c’était le cas.

Remarque
Les contrôles de saisie sont effectués dans tous les cas (CFXX, ENTER, CAXX)
Les contrôles de validité sont effectués uniquement dans cas (CFXX, ENTER)

Le programme RPGLE pour tester

**free
ctl-opt DFTACTGRP(*NO) ;
dcl-f Controle WORKSTN ;
  dou *in03 ;
    exfmt fmt01 ;
    if not *in03;
    endif ;
  // Contrôle des zones
   *in45 = *on ;
  enddo ;
  *inlr = *on ;

Remarque :
Dans cet exemple, on utilisera l’indicateur 45 pour ne plus affecter de valeur par défaut

Vous pouvez ainsi simplifier votre application d’une grande partie des contrôles basics

Vous pouvez indiquer , un message différent par le mot clé CHCKMSGID()

, , Utilisez de l’Unicode en 5250

Unicode permet d’encoder des caractères complexes sous deux octets

Un site pour avoir des informations supplémentaires

https://fr.wikipedia.org/wiki/Unicode

Vous voulez afficher des caractères Unicode dans votre session 5250,

parce que vous travaillez avec la chine par exemple.

Voici un petit exemple pour vous indiquer les grandes étapes

Rappel:

Pour avoir des caractères Unicode, vos zones doivent être déclarées comme ceci

NOM VARGRAPHIC(30) CCSID 1200 NOT NULL

Vous pouvez insérer des caractères dans votre table par SQL par exemple

Exemple chinois et russe

INSERT INTO NOMTBL (NOM) VALUES(
(‘张’), (‘Иванов’) )

Dans votre DSPF, vous pouvez déclarer zones par référence

niveau fichier
A REF(*LIBL/NOMTBL)

niveau zone
A NOM R O 6 4REFFLD(PERSONNES/NOM *LIBL/NOMTBL)

Vous obtiendrez le résultat suivant ;

Vous devrez également indiquer sur la commande de compile de l’écran (CRTDSPF),

le paramètre IGCDTA(*YES)

Votre session ACS devra supporté l’Unicode comme ceci

Votre programme en RPGLE par exemple n’aura aucune différence par rapport à des caractères latins

Voici le résultat d’un affichage

Remarque :


Vous pouvez faire beaucoup de choses
Tout n’est pas parfait , pas de solution simple pour utiliser les MSGID et MSGCON …

Vous devrez avoir un clavier qui vous permet de saisir les caractères souhaités

, , Ajouter des fichiers à une archive ZIP

Vous connaissez tous la commande CPYTOARCF qui permet de Zipper un fichier

Mais vous ne pouvez pas un fois généré lui ajouter un fichier !

On va essayer de vous aider

Dans les produits opensys vous avez la commande zip

Vous avez ce répertoire dans votre path (similaire à votre *LIBL)
$

echo $PATH
/QOpenSys/pkgs/bin:/usr/bin:.:/QOpenSys/usr/bin
$

Remarque
Vous pouvez le régler par le fichier .profile

https://www.ibm.com/support/pages/setting-path-environment-variable-include-current-working-directory-qshell

Vous pouvez donc zipper sous QSH ou QP2TERM

exemple

$

zip archive.zip analyse.csv
adding: analyse.csv (deflated 84%)
$

et par défaut si vous zippez sur une archive existante il ajoute

zip archive.zip xmlversion.txt
adding: xmlversion.txt (stored 0%)
$

pour voir le résultat

unzip -l archive.zip
Archive: archive.zip
Length Date Time Name
——— ———- —– —-
9934 2019-03-29 23:44 analyse.csv
17 2019-02-13 10:49 xmlversion.txt
——— ——-
9951 2 files
$

Pour vous aider nous proposons une commande ADDTOARCF que vous pouvez retrouver ici
https://github.com/Plberthoin/PLB/tree/master/GTOOLS/
un CLLE + un CMD

Remarque :

Vous pouvez ajouter une un fichier à un zip généré par CPYTOARCF
Par défaut il créera la l’archive
Vous pouvez indiquer des options si elles sont valides dans la commande Zip
Vous avez un fichier stdout.log dans votre répertoire courant

Simple et efficace !

, , Exécuter ACS à partir de votre partition

Vous voulez exécuter ACS à partir de votre IBMI

Exemple : la nouvelle fonction de génération des fichiers XLS

VALUES SYSTOOLS.GENERATE_SPREADSHEET(
PATH_NAME => ‘/home/plb/liste_options.xls’,
FILE_NAME => ‘QAUOOPT’,
LIBRARY_NAME => ‘QGPL’);

Le répertoire /QIBM/ProdData/Access/ACS est en *PUBLIC *EXCLUDE par défaut.
Voici une solution pour ouvrir en gardant la main sur les utilisateurs qui auront droit à cette possibilité

Création de la liste d’autorisation

CRTAUTL AUTL(ACS)
TEXT(‘Exécution ACS sur IBMi’)

On considère que votre installation est par défaut, on applique la liste dessus

CHGAUT OBJ(‘/QIBM/ProdData/Access/ACS’) AUTL(ACS) SUBTREE(*ALL)

Vous pouvez éditer vos utilisateurs

EDTAUTL AUTL(ACS)

Remarque:

Vous pouvez gérer les droits par groupe, mais le plus efficace c’est par utilisateur, vous voyez ainsi qui est autorisé directement.

, Mettez des relations dans votre DB

Vous êtes en train d’analyser votre data base et vous voulez mettre en place des relations sur celle-ci.

Je vais vous re présenter les contraintes d’intégralité référentielles
et plus précisément pour voir et comprendre les données en attente de validation .

Voici un petit exemple pour illustrer :
Considérons un fichier pour les employés et un pour les services services :


Création du fichier des services
CREATE OR REPLACE TABLE GDATA.CST2 (
SERVICE CHAR(3) CCSID 1147 NOT NULL DEFAULT  » ,
LIBEL CHAR(30) CCSID 1147 NOT NULL DEFAULT  » ,
CONSTRAINT GDATA.Q_GDATA_CST2_SERVICE_00001 PRIMARY KEY( SERVICE ) )

RCDFMT CST2F ;


1/ Création du fichier des employés avec une contrainte

CREATE OR REPLACE TABLE GDATA.CST1 (

NUMERO DECIMAL(5, 0) NOT NULL DEFAULT 0 ,
NOM CHAR(30) CCSID 1147 NOT NULL DEFAULT  » ,
PRENOM CHAR(30) CCSID 1147 NOT NULL DEFAULT  » ,
SERVICE CHAR(3) CCSID 1147 NOT NULL DEFAULT  » ,
PRIMARY KEY( NUMERO ) ,
CONSTRAINT GDATA.Q_GDATA_CST1_SERVICE_00001
FOREIGN KEY( SERVICE )
REFERENCES GDATA.CST2 ( SERVICE )
ON DELETE NO ACTION
ON UPDATE NO ACTION )

RCDFMT CST1F ;

Vous pouvez ajouter la contrainte ultérieurement avec

  • la commande :

ADDPFCST FILE(GDATA/CST1)
TYPE(REFCST) KEY(SERVICE) PRNFILE(GDATA/CST2) PRNKEY(SERVICE) DLTRULE(NOACTION)
UPDRULE(*NOACTION)

  • le SQL

ALTER TABLE GDATA.CST1
ADD CONSTRAINT GDATA.Q_GDATA_CST1_SERVICE_00001
FOREIGN KEY( SERVICE )
REFERENCES GDATA.CST2 ( SERVICE )
ON DELETE NO ACTION
ON UPDATE NO ACTION ;

2/ Alimentation des données

Création des services

INSERT INTO GDATA/CST2 VALUES(‘COM’, ‘Comptabilité’)
INSERT INTO GDATA/CST2 VALUES(‘PRO’, ‘Production ‘)

Création des employés

INSERT INTO GDATA/CST1 VALUES(01, ‘Berthoin’, ‘Pierre-Louis’, ‘COM’)
INSERT INTO GDATA/CST1 VALUES(02, ‘Berthoin’, ‘Younes ‘, ‘PRO’)

Sur une insertion avec service inexistant, un message d’erreur est produit

INSERT INTO GDATA/CST1 VALUES(03, ‘Berthoin’, ‘Yasmine ‘, ‘CRP’)

ID message . . . . . . : SQL0530

Message . . . . : Opération non admise par la contrainte référentielle
Q_GDATA_CST1_SERVICE_00001 de GDATA.

Sur une suppression de service avec des employés liés, un message d’erreur est produit

DELETE FROM GDATA/CST2 WHERE SERVICE = ‘PRO’

ID message . . . . . . : SQL0532

Message . . . . : Suppression impossible à cause de la contrainte
référentielle Q_GDATA_CST1_SERVICE_00001 de GDATA.

Il est possible de désactiver la contrainte :

CHGPFCST FILE(GDATA/CST1)
CST(‘Q_GDATA_CST1_SERVICE_00001’)
STATE(*DISABLED)

Une fois les contrôles désactivés, les requêtes précédentes s’exécutent

DELETE FROM GDATA/CST2 WHERE SERVICE = ‘PRO’

INSERT INTO GDATA/CST1 VALUES(03, ‘Berthoin’, ‘Yasmine ‘, ‘CRP’)

Lorsqu’on remet la contrainte :

CHGPFCST FILE(GDATA/CST1)
CST(‘Q_GDATA_CST1_SERVICE_00001’)
STATE(ENABLED) CHECK(YES)

Les valeurs de clé de la contrainte référentielle sont incorrectes.
Vérification en instance pour le fichier CST1.

Si vous avez des anomalies, vous devez désactiver la contrainte :

CHGPFCST FILE(GDATA/CST1)
CST(‘Q_GDATA_CST1_SERVICE_00001’)
STATE(*DISABLED)

Pour voir les enregistrements en attente de validation :

DSPCPCST FILE(GDATA/CST1)
CST(‘Q_GDATA_CST1_SERVICE_00001’)
OUTPUT(*)

Pas de service SQL mais un peu d’astuce et c’est ok

Il suffit de chercher les employés avec un service inexistant

CREATE TABLE QTEMP.ATTENTES AS
(SELECT *
FROM GDATA.CST1 A
WHERE NOT EXISTS (
SELECT *
FROM GDATA.CST2 B
WHERE A.SERVICE = B.SERVICE
AND B.SERVICE IS NOT NULL))
WITH DATA;

Remarque :

Vous pouvez passer cette commande avant de mettre en œuvre votre contrainte !
Vous pourrez ainsi mettre des relations dans votre application sans risque

Vous pouvez ensuite utiliser, un outil de modélisation :

https://gitmind.com/fr/schema-base-donnees.html

Vous avez également des extensions dans Visual Studio Code

ou utiliser un simple Chatgpt avec un prompt du style :

« Peux tu me faire un schéma format PNG des relations de ma base de données avec les scriptes ci joint  »

FK Foreign key

PK Primary key

Rien de magique , mais si on peut renseigner et documenter sa base, c’est toujours ça de fait