Dans la dernière TR est apparue une nouveauté très intéressante « API RSE », c’est un ensemble d’API REST fournies avec votre système d’exploitation au travers du serveur ADMIN5.


Ces APIs sont utilisables depuis le web et permettent de lancer des commandes, accéder à l’IFS, de lancer de requêtes SQL…

Ce service ne fonctionne qu’en TLS vous devrez donc le sécuriser par l’administration http ://Votre_systeme:2001/HTTPAdmin

Vous devez ensuite le démarrer s’il ne l’est pas c’est le serveur ADMIN5

==>STRTCPSVR SERVER(*IAS) INSTANCE(admin5)

Ce serveur tourne par défaut sur le port 2012

https://Votre_systeme:2012/openapi/ui/

Vous devrez vous authentifiez pour commencer utilisez un user et un mot de passe ibmi, vous cliquez sur authorize

Nous allons tester une commnde CL

Vous cliquez sur try input

Vous avez un flux json avec vos commandes IBMI à l’intérieur vous cliquez sur execute

Vous avez alors le résultat

A noter que vous avez le lien, en haut pour l’intégrer dans vos applications

Conclusion
C’est gratuit c’est technologies actuelles, testez les possibilités de ce service

Pour en savoir plus


la pause café de volubis ici : https://www.volubis.fr/Pausecaf/PAUSECAF91.html

le site IBM : https://www.ibm.com/support/pages/node/6982701

, Offrez une indexation à votre IBMi avec OMNIFIND

Il existe un produit sur #IBMi qui permet d’indexer des fichiers DB (zones), des spools, des membres sources et l’IFS.

De plus en plus vous utilisez l’IFS et il peut être intéressant d’indexer les fichiers utilisateurs dans /HOME par exemple,

voici ce qu’il vous faudra faire pour démarrer avec cette solution.

Vous devez avoir le produit (gratuit) 5733OMF

la page IBM est ici

https://www.ibm.com/support/pages/omnifind-ibm-i

Vous avez plusieurs services SQL qui vont vous permettre d’administrer ce serveur

1) Vous devrez d’abord le démarrer

Vous avez un server par défaut c’est le 1

call sysproc.systs_start(1)

Pour voir si votre server est démarré vous avez un service SQL

SELECT substr(SERVERNAME, 1, 30) as serveur
, SERVERSTATUS FROM QSYS2.SYSTEXTSERVERS

Attention 0 indique démarré et 1 arrêté

vous pouvez lui donner un nom comme ceci

UPDATE QSYS2/SYSTEXTSERVERS SET SERVERNAME = ‘NOM_SERVEUR’ WHERE
SERVERID = 1

2) Vous devez créer une collection qui contiendra les éléments nécessaires à l’administration et les index par exemple

create collection omnifind

CALL SYSPROC.SYSTS_CRTCOL(‘OMNI_COL’,‘FORMAT INSO’)

Vous pouvez indiquer la fréquence de mise à jour, par défaut, pas de mise à jour automatique.

3) Vous allez ensuite créer un index, ici un index sur l’IFS

Si vous voulez indexer /HOME et les sous répertoires vous devrez utiliser la procédure suivante

SET schema pour mettre OMNI_COL comme collection par défaut

CALL MYCOLLECTION.ADD_IFS_STMF_OBJECT_SET(‘/home/’);

3) Vous allez devoir lancer la mise à jour de l’indexation

call SYSPROC.SYSTS_UPDATE(‘OMNI_COL’ , ‘IFS_OMNI_COL’)

ca peut prendre du temps

4) Vous avez une procédure qui permet de rechercher SEARCH

Vous devrez être autorisé à cette procédure

SET CURRENT SCHEMA OMNI_COL

GRANT EXECUTE ON PROCEDURE SEARCH(VARCHAR) TO QPGMR

set schema omni_col ;

CALL SEARCH(‘TEXT’)

la procédure vous renvoi un result SET que vous pouvez intégrer dans un programme RPGLE par exemple

5) Vous pouvez utiliser un dictionnaire de synonyme

Le fichier modèle se trouvera ici

/QOpenSys/QIBM/ProdData/TextSearch/server1/config/spell/Synonymes.xml

<?xml version="1.0" encoding="UTF-8"?>
<synonymgroups version="1.0">
<synonymgroup>
<synonym>cheval</synonym>
<synonym>chevaux</synonym>
</synonymgroup>
 ...

</synonymgroups>

Pour importer

Vous devrez connaitre le nom de la collection

select * from qsys2.systextindexes

Puis passer le scripte sh suivant pour faire l’importation

QSH

cd /Qopensys/QIBM/ProdData/TextSearch/server1/bin

synonymTool.sh importSynonym

-synonymFile /QOpenSys/QIBM/ProdData/TextSearch/server1/config/spell/Synonymes.xml

-collectionName ‘nom_votre_collection’ true

-configPath /QOpenSys/QIBM/ProdData/TextSearch/server1/config

Quand vous rechercherez cheval, vous aurez les fichiers qui ont également chevaux dans le texte

Conclusion:

Ca peut être intéressant d’utiliser ce type d’index pour améliorer la performance de recherche
le produit est gratuit testez le !

, Comparer les PTF de 2 systèmes

Vous avez besoin de connaitre les niveaux de PTF de 2 systèmes.

Voici comment vous pouvez faire pour comparer les PTF de 2 systèmes, avant on pouvait le faire par Navigator for i – voir le post https://www.gaia.fr/comparer-le-niveau-de-ptf-entre-2-systemes-ibmi/

Pour les groupes

Vous avez la vue QSYS2.GROUP_PTF_INFO

Vous allez devoir comparer les niveaux installés sur les 2 systèmes. Voici comment le faire simplement :

Vous devrez faire une extraction des éléments sur le système à comparer par exemple

create table gaia.remote_ptf as (
select * from QSYS2.GROUP_PTF_INFO
) with data

Vous envoyez le fichier sur la machine cible

select a.PTF_GROUP_NAME, a.PTF_GROUP_LEVEL, b.PTF_GROUP_LEVEL
from QSYS2.GROUP_PTF_INFO a join gaia.remote_ptf b on
A.PTF_GROUP_NAME = B.PTF_GROUP_NAME

pour n’avoir que les différences

select distinct
substr(a.PTF_GROUP_NAME, 1, 30) ,
a.PTF_GROUP_LEVEL, b.PTF_GROUP_LEVEL
from QSYS2.GROUP_PTF_INFO a join gaia.remote_ptf b on
A.PTF_GROUP_NAME = B.PTF_GROUP_NAME
where a.PTF_GROUP_LEVEL <> b.PTF_GROUP_LEVEL

Attention vous avez 2 niveaux de groupe dans le fichier, il faudrait améliorer le script en prenant un max pour avoir le plus haut sur les 2 systèmes

Exemple :

with
LCL (PTF_GROUP_NAME, PTF_GROUP_LEVEL) as
(
SELECT substr(PTF_GROUP_NAME, 1, 20), max(PTF_GROUP_LEVEL) FROM
QSYS2.GROUP_PTF_INFO GROUP BY PTF_GROUP_NAME
),
RMT (PTF_GROUP_NAME, PTF_GROUP_LEVEL) as
(
SELECT substr(PTF_GROUP_NAME, 1, 20), max(PTF_GROUP_LEVEL) FROM
gaia.remote_ptf GROUP BY PTF_GROUP_NAME
)
select A.PTF_GROUP_NAME, A.PTF_GROUP_LEVEL, B.PTF_GROUP_LEVEL
from LCL A join RMT B on A.PTF_GROUP_NAME = B.PTF_GROUP_NAME

Pour les PTF unitaires

Vous avez la vue QSYS2.PTF_INFO, vous pouvez également utiliser un DSPPTF en OUTFILE

Vous allez devoir trouver les PTF manquantes

Vous devrez faire une extraction des éléments sur le système à comparer par exemple

create table gaia.remote_ptf1 as (
select * from QSYS2.PTF_INFO
) with data

Vous envoyez le fichier sur la machine cible

Pour avoir les PTF qui manquent sur le remote :

SELECT a.PTF_PRODUCT_ID, a.PTF_IDENTIFIER
FROM QSYS2.PTF_INFO a exception join
gaia.remote_ptf1 b on
a.PTF_PRODUCT_ID = b.PTF_PRODUCT_ID and
a.PTF_IDENTIFIER = b.PTF_IDENTIFIER

Si voulez les PTF qui manquent sur la source, le plus simple est de changer l’ordre des fichiers :

SELECT a.PTF_PRODUCT_ID, a.PTF_IDENTIFIER
FROM gaia.remote_ptf1 a exception join
QSYS2.PTF_INFO b on
a.PTF_PRODUCT_ID = b.PTF_PRODUCT_ID and
a.PTF_IDENTIFIER = b.PTF_IDENTIFIER

Remarque :

Vous pouvez utiliser une connexion DRDA pour comparer vos fichiers sans les envoyer, si c’est paramétré chez vous
exemple :
select distinct
substr(a.PTF_GROUP_NAME, 1, 30) ,
a.PTF_GROUP_LEVEL, b.PTF_GROUP_LEVEL
from QSYS2.GROUP_PTF_INFO a join .QSYS2.GROUP_PTF_INFO b on
A.PTF_GROUP_NAME = B.PTF_GROUP_NAME
where a.PTF_GROUP_LEVEL <> b.PTF_GROUP_LEVEL

Vous avez des outils comme ARE qui permettent de faire ce type d’opération


un lien avec un exemple DSPPTF OUTFILE
https://www.ibm.com/support/pages/ptfs-comparing-ptfs-between-systems

, Faire un CSV avec SQL

Il existe plusieurs solutions pour faire du CSV, la plus connue c’est en utilisant la commande CPYTOIMPF, mais vous pouvez générer directement un fichier CSV en utilisant SQL, voici un petit tutoriel pour vous aider :

Vous devrez utiliser les procédures QSYS2.IFS_WRITE*

https://www.ibm.com/docs/en/i/7.4?topic=is-ifs-write-ifs-write-binary-ifs-write-utf8-procedures

Voici un exemple qui comporte la génération du fichier, l’ajout d’un entête et la génération des listes de détail. Nous avons choisi de faire sans délimiteur et avec « ; » comme séparateur. Le fichier obtenu est directement lisible par Excel.

Si vous voulez un délimiteur voici une variante sur les select avec  » comme délimiteur

Pour les entêtes de ligne :

LINE => ‘ »Les_options » ; « Les_commandes »‘)

Pour les lignes de détail, on enlève les blancs :

select ‘ »‘ concat trim(option) concat ‘ » ; « ‘ concat trim(command) concat ‘ »‘ as option_txt from qgpl.qauoopt

BEGIN
  -- Créér ou remplacer le fichier dans l'IFS
  CALL QSYS2.IFS_WRITE_UTF8(PATH_NAME =>'les_options_pdm.csv', 
                       LINE => '', 
                       OVERWRITE => 'REPLACE', 
                       END_OF_LINE => 'NONE');
  -- Mettre l'entête de colonne                     
  CALL QSYS2.IFS_WRITE_UTF8(PATH_NAME =>'les_options_pdm.csv', 
                       LINE => 'Les_options ; Les_commandes'); 
  -- Ecriture d'une ligne obtenue dans le select  
  FOR select option concat ';' concat command  as option_txt from qgpl.qauoopt DO
    CALL QSYS2.IFS_WRITE_UTF8(PATH_NAME => 'les_options_pdm.csv', 
                         LINE => option_txt);
  END FOR;
END;

Dans cet exemple, on a utilisé la procédure QSYS2.IFS_WRITE_UTF8 pour générer le fichier directement en UNICODE et éviter les problèmes de CCSID, c’est le sens de l’histoire …

Nous n’avons pas précisé de répertoire. Le fichier est créé dans le répertoire par défaut de l’utilisateur, en principe /home/<user>

.

Conclusion :

C’est une solution simple et efficace qui permet de générer un fichier sans passer par un fichier intermédiaire en DB2.

Si vos zones sont numériques vous devrez les convertir par la fonction CHAR()

Merci Nath pour ton aide.

Il est difficile de déboguer un watcher parce qu’on ne maitrise pas son lancement.

Voici une méthode en utilisant RDI, qui va vous permet de le faire :

  1. Trouver le nom du programme à analyser :

WRKWCH WCH(*ALL) :

  • 5 pour le détail
  • Dans RDI, clic droit sur le programme à déboguer => débogage ou couverture de code (entrée de service) => définir un point d’entrée de service

Le message d’affiche :

Pour tester, on peut simuler un traitement qui va planter. Dans notre cas, on fait un call d’un programme qui n’existe pas, et donc ça va faire un plantage dans QSYSOPR.

SBMJOB CMD(CALL PGM(GAIA/ERREURA)) 

        JOB(ERREURA)                

        JOBQ(QSYSNOMAX)         

Une fois le programme a été lancé, sur RDI s’affichera le message suivant :

Cliquer sur « Afficher *LISTING »

Pour avancer d’un pas on peut utiliser la touche F5 ou en cliquant sur la flèche :

Pour afficher les valeurs des variables il suffit de passer la souris sur le nom de la variable :

Conclusion : c’est une solution simple pour déboguer un watcher ou un programme dont vous ne maitrisez pas le lancement.

Le programme doit être compilé avec le source.

Vous devrez avoir le droit pour faire ce type d’opération. Soit au niveau de profil, soit par les fonctions usages.

, , Informations sur les SAVF

Les groupes DB2 pour la TR2 de la V7R5 et de la TR8 de la V7R4 sont disponibles, une des nouveautés c’est les vues sur les fichiers de sauvegarde

La première vue sur les SAVF SAVE_FILE_INFO permet d’avoir des informations sur le SAVF

par exemple
vous voulez connaitre les SAVF qui date de plus de 6 mois

select * from QSYS2.SAVE_FILE_INFO
where SAVE_TIMESTAMP < current date – 6 month
order by SAVE_TIMESTAMP desc

Vous pouvez par exemple utiliser la fonction SQL QCMDEXC pour faire le ménage plus d’informations ici
https://www.gaia.fr/qcmdexc-en-fonction-sql/

La deuxième vue sur les objets sauvegardés dans les SAVF, QSYS2.SAVE_FILE_OBJECT permet d’avoir des informations sur les ojets contenus dans le SAVF

Par exemple vous voulez savoir, si un objet est dans une sauvegarde et sa date de sauvegarde

select * from QSYS2.SAVE_FILE_OBJECTS
where OBJECT_NAME = ‘votre objet’ and OBJECT_TYPE = ‘votre type’
order by SAVE_TIMESTAMP desc

Attention
Ces fonctions sont à lancer en batch, c’est des informations qui mettent du temps à être extraites

, Migration en V7R4 et IFS

Il est possible que vous ayez un effet de bord sur les fichiers téléchargés par FTP ou SFTP par exemple dans vos cpyfrmstmf ou cpyfrmimpf vous avez un plantage.

Les fichiers étaient jusqu’ici encodés en CCSID = 819 et maintenant par défaut, ils sont encodés en CCSID = 1208

Le problème est référencé ici

https://www.ibm.com/support/pages/after-v7r4-upgrade-encoding-scheme-not-compatible-utilizing-gifsgatecpyfrmstmf-gentran-server-iseries

En résumé, vous devez rajouter une variable d’environnement et redémarrer vos services

Voici comment ?

// Ajout d’une variable d’environnement

ADDENVVAR ENVVAR(PASE_DEFAULT_UTF8) VALUE(N) LEVEL(*SYS)

// Redémarrage du FTP

STRTCPSVR SERVER(*FTP)

ENDTCPSVR SERVER(*FTP)

// Redémarrage du SFTP

ENDTCPSVR SERVER(*SSHD)

STRTCPSVR SERVER(*SSHD)

Conclusion :

Ca vous permet de contourner le problème, mais le mieux est de passer en unicode donc CCSID = 1208

Les fonctions géospatiales

Premier test sur les fonctions géospatiales, elles sont désormais intégrées à DB2

Vous pouvez indiquer les coordonnées GPS d’un lieu dans une zone, et vous pourrez ensuite faire des calculs,
de distance , de superficie, etc …

C’est des zones de type QSYS2.ST_POINT, par exemple pour indiquer des coordonnées GPS, mais vous pouvez également indiquer des formes comme des lignes ou des polygones ..

Voici un premier exemple

— Création table des salariés avec leur lieu de travail

create table GDATA.SALARIE
(ID int,
NOM varchar(30),
PRENOM varchar(30),
MAISON QSYS2.ST_POINT,
TRAVAIL QSYS2.ST_POINT);

— Insertion dans la table des informations
Vous pouvez les trouver ici les coordonnées GPS:
https://www.coordonnees-gps.fr/

le gouvernement mais également à disposition un site

https://adresse.data.gouv.fr/api-doc/adresse

Vous pouvez interroger par CURL ou API bien sur par API en SQL

Exemple pour Gaia:

sous qsh

curl « https://api-adresse.data.gouv.fr/search/?q=41+rue+diebold&postcode=69009 »

résultat

Dans un browser

https://api-adresse.data.gouv.fr/search/?q=41+rue+Diebold&postcode=69009

INSERT INTO GDATA.SALARIE VALUES(1, ‘Géronimo’, ‘Cohen’,
QSYS2.ST_POINT(‘point (45.7542616 4.9152559)’),
QSYS2.ST_POINT(‘point (45.7726 4.8033)’)
) ;

Par Api

VALUES QSYS2.HTTP_GET(
‘https://api-adresse.data.gouv.fr/search/?q=41+rue+Diebold&postcode=69009’);

— Calculé la distance entre 2 points en mètres
— Représentation en coordonnées des zones

SELECT
ST_ASTEXT(maison) as coord_maison,
ST_ASTEXT(travail) as coord_travail,
st_distance(maison , travail) as distance from GDATA.SALARIE ;

Résultat :

.

Vous pouvez par exemple, facilement calculer les salariés qui habitent à plus de 100 km de leur lieu de travail.

SELECT « ID », NOM, PRENOM
from GDATA.SALARIE
where st_distance(maison , travail) > 100000 ;

On complète

— Création table des docteurs
create table GDATA.DOCTEUR
(ID int,
NOMDOC varchar(30),
VILLE varchar(30),
CABINET QSYS2.ST_POINT);

— insertion d’une liste de docteurs

INSERT INTO GDATA.DOCTEUR VALUES(1, ‘Docteur1’, ‘Lyon’,
QSYS2.ST_POINT(‘point (45.7679223 4.8445736)’)
) ;

INSERT INTO GDATA.DOCTEUR VALUES(2, ‘Docteur2’, ‘Marseille’,
QSYS2.ST_POINT(‘point (43.2978337 5.3693324)’)
) ;

INSERT INTO GDATA.DOCTEUR VALUES(3, ‘Docteur3’, ‘Paris’,
QSYS2.ST_POINT(‘point (48.8532238 2.3678865)’)

) ;

— Je veux les docteurs à moins de 10 km du domicile du salarié

Select b.nomdoc, b.ville, st_distance(a.maison , b.cabinet) as distance
from gdata.salarie a , gdata.docteur b
where st_distance(a.maison , b.cabinet) < 10000 ;

Le résultat

Conclusions :

Il y a des fonctions beaucoup plus poussées, et on imagine bien le type d’application qu’on pourra faire, donc on peut prévoir dès à présent une zone de géolocalisation dans des fichiers clients qu’on va créer, voir modifier .

Plus d’informations ici

https://www.ibm.com/docs/en/i/7.5?topic=analytics-geospatial-functions

, Comment Modifier un spool ?

Vous avez un spool généré et vous voulez le modifier, bien sur si vous pouvez agir avant la génération du spool c’est mieux.

Imaginons que vous ne pouvez pas le faire, voici la procédure en quelques étapes pour réaliser cette opération.

Vous devez créer un fichier qui a la longueur de votre spool + 1

CRTPF QTEMP/SPOOLPF RCDLEN(longueur + 1)

Ensuite vous avez besoin d’identifier votre spool
nom_spool, Numero_job, Utilisateur, Nom_job et numero_spool (souvent , on peut utiliser *LAST)

Vous allez copier votre spool en idiquant bien *FCFC

CPYSPLF FILE(NOM_SPOOL) TOFILE(QTEMP/SPOOLPF)
JOB(NUMERO_JOB/UTILISATEUR/NOM_JOB)
SPLNBR(LAST) CTLCHAR(*FCFC)

Vous pouvez alors modifier votre ficher DB généré, par SQL, DFU ou par programme

Votre fichier est modifié, vous allez devoir le recopier pour regénérer un spool.
D’abord, indiquez que vous avez besoin des caractères de contrôle


OVRPRTF FILE(NOM_SPOOL) CTLCHAR(*FCFC)


Transformation de votre fichier DB en SPOOL


CPYF FROMFILE(QTEMP/SPOOLPF) TOFILE(NOM_SPOOL)

Vous pouvez à nouveau gérer votre spool, exemple pour le changer de file :


CHGSPLFA FILE(NOM_SPOOL) JOB(NUMERO_JOB/UTILISATEUR/NOM_JOB)
SPLNBR(*LAST) OUTQ(TLXOFC/FAX)

Conclusion :

Ca reste du bricolage, mais ca peut dépanner.

, Messages CPF1124 et CPF1164

Quand un travail démarre, il crée dans la log système un message CPF1124 et un message CPF1164 quand il se termine.

C’est comme ca qu’on sait qu’un job à tourné

Mais attention, Il existe des travaux pour lesquels les messages CPF1124 et CPF1164 ne sont pas logués dans QHST : il s’agit des SPAWN jobs.

Les travaux QP0ZSPWP & QP0ZSPWT en sont de bons exemples.

Spawn batch jobs : https://www.ibm.com/docs/en/i/7.4?topic=jobs-spawn-batch

Spawn est une fonction qui crée un nouveau processus de travail (processus enfant) qui hérite de nombreux attributs du processus appelant (processus parent). Un nouveau programme est spécifié et commence à s’exécuter dans le processus enfant. Lorsque vous lancez un travail par lots, vous utilisez un travail parent pour transmettre des arguments et des variables d’environnement au travail enfant. L’API spawn() utilise des travaux batch immédiats, des travaux pré-démarrés ou des travaux batch pré-démarrés.

https://www.ibm.com/docs/en/i/7.4?topic=ssw_ibm_i_74/apis/spawn.htm

https://www.ibm.com/docs/en/i/7.4?topic=programs-example-using-process-related-apis

Ca peut être le cas aussi pour les jobs QCTXDMON (IBM transformer)

plus rigolo

Vous pouvez demander à supprimer ces messages

Pour cela vous devez créer une dtaara QWTFMSG dans QUSRSYS :

CRTDTAARA DTAARA(QUSRSYS/QWTFMSG) TYPE(*CHAR) LEN(14) VALUE(‘CPF1124CPF1164’)

Cette valeur est prise en compte au démarrage de vos sous systémes

elle est globale c’est dommage qu’on ne puisse préciser un sous système

Attention


Beaucoup d’outils d’analyse utilise ces messages pour vérifier le bon traitement d’une tache