, , , Renommer votre serveur LDAP Pour EIM

Vous utilisez la solution de single signon sur IBMi à base de kerberos et EIM

Votre serveur LDAP change de nom

Voici la liste des opérations à effectuer

Sur le serveur LDAP, vous n’avez rien à faire

Sur le serveur Kerberos

Vous avez 2 modifications à faire

Changer le nom du KDC sur l’onglet principal

Changer le nom du serveur de mot de passe sur l’onglet Serveur de mot de passe

Sur le serveur EIM

Sur le domaine changer le registre kerberos

Créer un nouveau registre utilisateurs de type source kerberos

et vous devrez ensuite sur chaque inscription remplacer votre source par le nouveau serveur

Ca peut être long si vous n’avez pas d’outils pour le faire

Notre produit GEIM peut vous aider dans cette tache !

, , , QCMDEXC en Fonction SQL

Depuis la TR4 de la version V7R4, vous pouvez utiliser la fonction QCMDEXC

C’est l’occasion de faire un rappel sur les différents usages disponibles jusque la

1 ) C’est une API (un programme) que vous pouvez appelez depuis un programme RPG ou CLP

en RPGLE

Dcl-Pr Exec_Commande QCMDEXC ExtPgm(‘QCMDEXC’);
Cmd Char(3000) Const;
CmdLen packed(15:5) Const;
End-Pr;

Dcl-S Gbl_Cmd Char(3000);

Gbl_Cmd = ‘Votre commande’ ;

Exec_commande(Gbl_Cmd : %len(Gbl_Cmd)) ;

En CLLE

PGM
DCL &CMD *CHAR 300
DCL &LEN *DEC (15 5)

CHGVAR &CMD (‘VOTRE COMMANDE’)
CHGVAR &LEN %LEN(&CMD)
CALL QCMDEXC (&CMD &LEN)

2) C’est une procédure SQL

call qcmdexc(‘votre commande’)

en SQL embarqué

Dcl-S Gbl_Cmd Char(3000);

call qcmdexc(:Gbl_Cmd)

3) C’est une Fonction SQL à partir de la TR4

Réorganisation des fichiers BD

SELECT qcmdexc(‘RGZPFM FILE(‘ concat
trim(substr(TABLE_SCHEMA, 1 , 10))
concat ‘/’ concat
substr(TABLE_NAME, 1 , 10) concat ‘)’) as résultat
FROM systables WHERE TABLE_SCHEMA =
‘GDATA’ and FILE_TYPE = ‘D’

la fonction renvoi 1 si ok et -1 si ko

Conclusion :
Vous avez un aperçu des possibilités qcmdexc sur la machine, à vous de jouer !

, , , Surveillez vos requêtes SQL sur votre #IBMi

Il est possible que vous ayez des doutes sur les performances de vos requêtes SQL, voici comment avoir une idée rapide de ce qui tourne

On va utiliser ACS
dans Base de données choisir
SQL Performance center

Vous avez un onglet Affichage des instructions

Vous choisissez le filtre à appliquer, ici on choisit les actives, vous pouvez être beaucoup plus pertinent en limitant votre choix.

Une fois que vous avez repéré une requête candidate, il vous suffit de faire un clic droit sur celle ci et vous pouvez lancer directement Visual Explain, qui vous expliquera le comportement de cette requête, vous pourrez alors faire les ajustements qui s’imposent

Le résultat dans V-E

PS:
Le principal critère de performance sur SQL, c’est les index, pensez à surveiller les suggestions faites par Index Advisor

Une des nouveautés de TR4 c’est Query Supervisor

L’idée est de limiter les requêtes selon certain critères (de temps d’exécution, d’espace temporaire occupé etc… )
Jusqu’à présent c’était pas toujours simple et un peu binaire

Ajout d’un seuil à contrôler

Se fait par la procédure QSYS2.ADD_QUERY_THRESHOLD

Exemple

CALL QSYS2.ADD_QUERY_THRESHOLD(THRESHOLD_NAME => ‘Seuil’,
THRESHOLD_TYPE => ‘CPU TIME’,
THRESHOLD_VALUE => 1,
INCLUDE_USERS => ‘PLB’,
DETECTION_FREQUENCY => 60)

Vous devez indiquer :
– Un nom ici Seuil
– Le seuil à contrôler
– Une valeur pour ce seuil
– Un filtre d’inclusion ou d’exclusion ici inclusion du profil PLB
– Un délai de rafraichissement en seconde

Vous avez une vue qui permet de voir les seuils définis sur votre partition

C’est la vue QUERY_SUPERVISOR

exemple

voir tous les seuils définis pour Query supervisor

SELECT *
FROM QSYS2.QUERY_SUPERVISOR ORDER BY THRESHOLD_TYPE, THRESHOLD_VALUE DESC;

;

Vous pouvez indiquer un programme d’exit QIBM_QQQ_QRY_SUPER

ci joint un exemple basique pour expliquer ce qui ce passe

pgm parm(&qrysupdta &returncod)
/* Paramètres */
dcl &qrysupdta *char 1024
dcl &returncod char 8

/* Variables de Travail */

DCL VAR(&SIZ_HEADER) TYPE(CHAR) LEN(4) +
STG(DEFINED) DEFVAR(&qrysupdta 1)

DCL VAR(&FMT_NAME) TYPE(CHAR) LEN(8) +
STG(DEFINED) DEFVAR(&qrysupdta 5)

DCL VAR(&JOB_NAME) TYPE(CHAR) LEN(10) +
STG(DEFINED) DEFVAR(&qrysupdta 13)

DCL VAR(&JOB_USER) TYPE(CHAR) LEN(10) +
STG(DEFINED) DEFVAR(&qrysupdta 23)

DCL VAR(&JOB_NUMBER) TYPE(CHAR) LEN(6) +
STG(DEFINED) DEFVAR(&qrysupdta 33)

DCL VAR(&SUBSYSTEM) TYPE(CHAR) LEN(10) +
STG(DEFINED) DEFVAR(&qrysupdta 39)

DCL VAR(&Usr_name) TYPE(CHAR) LEN(49) +
STG(DEFINED) DEFVAR(&qrysupdta 23)

DCL VAR(&QRYPLANID) TYPE(CHAR) LEN(08) +
STG(DEFINED) DEFVAR(&qrysupdta 67)

DCL VAR(&THR_NAME) TYPE(CHAR) LEN(60) +
STG(*DEFINED) DEFVAR(&qrysupdta 75)
dcl &msg *char 2056
chgvar &msg (&JOB_NAME *cat ‘/’ *cat &JOB_USER *tcat ‘/’ *tcat +
&JOB_NUMBER *bcat ‘Arreté pour dépassement, ‘ *bcat &THR_NAME)
SNDUSRMSG MSG(&MSG)
/* on force l’arret de la requete */
CHGVAR VAR(%BIN(&returncod 1 4)) VALUE(1)
ENDPGM
Pour en savoir plus le lien ici

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

Le message ne cas de débordement

Le message remonté depuis notre programme d’exit

Vous pouvez voir vos statistiques de sollicitation dans ACS SQL performance center

Vous pouvez enlever vos seuils

c’est la procédure REMOVE_QUERY_THRESHOLD

CALL QSYS2.REMOVE_QUERY_THRESHOLD(THRESHOLD_NAME => ‘Seuil’);

vous indiquez le nom que vous avez donné à votre seuil

Conclusion

C’est une bonne nouveauté pour les administrateurs DB2

On peut regretter l’absence du procédure de change qui permettrait de revenir sur les paramètres de définition.

, , UTILISATION DES API EN SQL

Récupérer une API

Il existe un grand nombre d’API aux fonctionnalités diverses dont certaines nous permettent de récupérer des données structurées dans différents formats (XML, JSON, …).

Grace aux fonctions SQL de l’IBMi nous pouvons récupérer ces données pour les insérer dans les fichiers de la base de données.

Pour les exemples qui suivent, on se base sur trois API tirées du site https://openweathermap.org/ :

  • Une première qui récupère la météo dans une ville donnée

https://api.openweathermap.org/data/2.5/weather?q={city name}&appid={API key}&mode=xml’

  • Une qui récupère jusqu’à 50 communes autour de coordonnées choisies

https://api.openweathermap.org/data/2.5/find?lat=45.75&lon=4.5833&cnt=50&appid={API key}&mode=xml

  • Une qui récupère jusqu’à des communes dans un rectangle de coordonnées choisies

https:// api.openweathermap.org/data/2.5/box/city?bbox=4,45,8,46,50&appid={API key}

Extraire les données de l’API

Sortie API en XML

La commande SQL suivante permet d’afficher les données dans un champ DATA 

SELECT DATA FROM (values
char(SYSTOOLS.HTTPGETCLOB('https://api.openweathermap.org/data/2.5/weather?q={city name}&appid={API key}&mode=xml',''), 4096))
ws(data);

Sortie API en JSON

La commande SQL suivante permet d’afficher les données dans un champ DATA 

SELECT DATA FROM (values
char(SYSTOOLS.HTTPGETCLOB('api.openweathermap.org/data/2.5/weather?q={city name}&appid={API key}',''), 4096))
ws(data);

Sortie API en HTML

La commande SQL suivante permet d’afficher les données dans un champ DATA 

SELECT DATA FROM (values
char(SYSTOOLS.HTTPGETCLOB('https://api.openweathermap.org/data/2.5/weather?q={city name}&appid={API key}&mode=html',''), 4096))
ws(data);

Récupération des données

En XML

On crée un fichier qui contiendra les colonnes que l’on veut récupérer (Ville, Température en cours, date, …)

CREATE TABLE GG/METEODB
(VILLE_ID DECIMAL (9, 0) NOT NULL WITH DEFAULT,
VILLE_NOM CHAR (50) NOT NULL WITH DEFAULT,
TEMPERATURE DECIMAL (5, 2) NOT NULL WITH DEFAULT,
TEMP_MIN DECIMAL (5, 2) NOT NULL WITH DEFAULT,
TEMP_MAX DECIMAL (5, 2) NOT NULL WITH DEFAULT,
DATE_MAJ CHAR (20) NOT NULL WITH DEFAULT)
;

Récupérer les données de l’API dans le fichier créé :

INSERT INTO GG.METEODB
select xdata.* FROM xmltable('$doc/cities/list/item'
PASSING XMLPARSE(document SYSTOOLS.HTTPGETCLOB('https://api.openweathermap.org/data/2.5/find?lat=45.75&lon=4.5833&cnt=10&appid={API key}&mode=xml','')) AS "doc"
COLUMNS
ville_id decimal(9, 0) PATH 'city/@id',
ville_nom varchar(50) PATH 'city/@name',
temperature decimal(5, 2) PATH 'temperature/@value',
temp_min decimal(5, 2) PATH 'temperature/@min',
temp_max decimal(5, 2) PATH 'temperature/@max',
date_maj varchar(20) PATH 'lastupdate/@value' ) as xdata;

En JSON

Contrairement à XML, on peut créer tout de suite un fichier qui contiendra les colonnes que l’on veut récupérer.

CREATE TABLE GG.METEOBD
(VILLE_ID DECIMAL (9, 0) NOT NULL WITH DEFAULT,
VILLE_NOM CHAR (50) NOT NULL WITH DEFAULT,
TEMPERATURE DECIMAL (5, 2) NOT NULL WITH DEFAULT,
TEMP_MIN DECIMAL (5, 2) NOT NULL WITH DEFAULT,
TEMP_MAX DECIMAL (5, 2) NOT NULL WITH DEFAULT,
DATE_UX_MAJ DECIMAL (12, 0) NOT NULL WITH DEFAULT)

Récupérer les données de l’API dans le fichier créé :

INSERT INTO GG.METEOBD
select * from JSON_TABLE(SYSTOOLS.HTTPGETCLOB('https://api.openweathermap.org/data/2.5/box/city?bbox=4,45,8,46,50&appid={API key}','') ,
'$.list[*]'
COLUMNS
(ville_id decimal(9, 0) PATH '$.id',
ville_nom varchar(50) PATH '$.name',
temperature decimal(5, 2) PATH '$.main.temp',
temp_min decimal(5, 2) PATH '$.main.temp_min',
temp_max decimal(5, 2) PATH '$.main.temp_max',
date_ux_maj decimal(12, 0) PATH '$.dt'));

Pour aller plus loin

En utilisant une API de LA POSTE qui ne nécessite pas d’inscription au préalable, ni d’identification. Nous pouvons réaliser un programme qui nous aide à retrouver une commune à partir d’un code postal, dans l’optique d’aider au remplissage de certains formulaires.
On crée un fichier temporaire en interrogeant directement l’API.

, , Variables SQL utilisables dans vos scripts ?

Voici quelques variables que vous pouvez utiliser dans vos requêtes SQL

par exemple Client_Ipaddr qui est arrivée avec la TR4

Quelques registres et variables d’environnement

select
current time as heure_en_cours,
current date as date_en_cours,
current user as utilisateur_courant,
current timestamp as timestamp_en_cours,
CURRENT CLIENT_ACCTNG as Client_connexion,
CURRENT CLIENT_APPLNAME as Client_Application,
Current timezone as Fuseau_Horaire,
Current server as Current_Server ,
current path as Current_path,
CURRENT CLIENT_APPLNAME as Programme_client,
CURRENT CLIENT_USERID as Utilisateur_client,
CURRENT CLIENT_PROGRAMID as Programme_client
from sysibm.sysdummy1

Quelques Variables globales dans SYSIBM

select
SYSIBM.Client_Host as Client_Host,
SYSIBM.Client_Ipaddr as Client_Ipaddr,
SYSIBM.Client_Port as Client_Port,
SYSIBM.Package_Name as Package_Name,
SYSIBM.Package_Schema as Package_Schema,
SYSIBM.Package_Version as Package_Version,
SYSIBM.Routine_Schema as Routine_Schema,
SYSIBM.Routine_Specific_Name as Routine_Specific_Name,
SYSIBM.Routine_Type as Routine_Type
from sysibm.sysdummy1

Comme dans nos exemples, ces variables sont utilisables dans vos requêtes

exemple

les travaux actifs de l’utilisateur en cous

, , Conversion d’une OUTQ en PDF par GENERATE_PDF

Depuis la TR4 de la V7R4,vous avez une fonction qui génère un PDF à partir d’un spool.

Voici une requête qui convertit les spools de votre outq en PDF

On va créer une variable globale pour indiquer le répertoire de génération des PDF

CREATE OR REPLACE VARIABLE QGPL.REPERT_PDF VARCHAR(30)DEFAULT ‘/home/PDF/’

Exécution de la requête sur votre outq

SELECT SPOOLED_FILE_NAME, JOB_NAME, FILE_NUMBER ,
SYSTOOLS.GENERATE_PDF(JOB_NAME => JOB_NAME ,
SPOOLED_FILE_NAME => SPOOLED_FILE_NAME ,
SPOOLED_FILE_NUMBER => FILE_NUMBER,
PATH_NAME => REPERT_PDF concat current date concat ‘_’ concat regexp_replace(JOB_NAME, ‘/’,  ») concat ‘_’ concat
SPOOLED_FILE_NAME concat ‘_’ concat FILE_NUMBER concat ‘.pdf’)
FROM QSYS2.OUTPUT_QUEUE_ENTRIES_BASIC WHERE OUTPUT_QUEUE_NAME = ‘votre_outq’

Le résultat vu par un WRKLNK


C’est juste un exemple, à vous de l’ajuster

, , , Les traitements asynchrones sur IBMi


Une définition simple, ce sont des traitements qui se déclenchent pour traiter des entrées d’une pile et qui ne renvoient pas de résultats directs au proccess émetteur

Il existe des produits spécifiques pour faire ça, sur l’IBMi le plus connu est bien sur mqseries .
Mais il est maintenant possible d’installer des produits open source comme RabbitMQ , etc…

Il existe également des solutions natives de la plateforme.

Parmi ces solutions il y a 2 méthodes

  • Cyclique ( toutes les 30 secondes)
  • A l’événement qui ne se déclencheront qu’en cas de nécessité (exemple triggers)

On ne présentera ici que les secondes.

Les triggers

Ce sont des programmes qu’on va enregistrer au niveau de la base de données, ils vont se déclencher sur un update, insert ou delete avant ou après l’action.

On peut les déclarer par commande ADDPFTRG ou par l’instruction SQL CREATE TRIGGER, on peut être plus précis sur l’exécution en SQL (Niveau zone modifiée par exemple)

Les DTAQs

Ce sont des files d’attentes que l’on crée par CRTDTAQ , on peut écrire dedans par API (QSNDDTAQ, QRCVDTAQ) ou par SQL QSYS2.SEND_DATA_QUEUE() et QSYS2.RECEIVE_DATA_QUEUE()

Pour la réception, on peut indiquer un temps négatif souvent -1, et le traitement se déclenchera quand il y aura un entrée dans la file !

soit dans le programme de traitement
CALL PGM(QRCVDTAQ) PARM(&DTAQNOM &DTAQBIB &DTAQLEN
&DATA &WAIT)
/* &wait = -1 */

Les msgqs en wait

historiquement, souvent utilisé, par exemple pour superviser la msgq qsysopr

dans le programme de traitement qui boucle sur cette instruction
RCVMSG … WAIT(*MAX)

Les fichiers à fin retardée

Le principe est le suivant, votre programme attendra un enregistrement quand il aura fini de lire les enregistrements trouvés

Avant le programme RPGLE
OVRDBF FILE(VOTREFIC) EOFDLY(99999)

dans le programme RPGLE

dou %eof() ;
….
read VOTREFIC ;

endif ;

Les watchers


Permettent d’analyser en temps réels des messages qui arrive dans les joblog, les historiques de log voir une autre file de message (MSGQ) .
Pour démarrer un watcher, on utilise la commande STRWCH
STRWCH SSNID(ANAWCH) WCHPGM(votre bib/votre programme) +
CALLWCHPGM(WCHEVT) WCHMSG((ALL))
WCHMSGQ((Votre bib/votre msgq))

votre programme reçoit 4 paramètres
L’option, la session, l’erreur et la donnée du message

exemple

/* Paramètres reçus */

DCL VAR(&WCHOPTION) TYPE(CHAR) LEN(10)

DCL VAR(&SESSIONID) TYPE(CHAR) LEN(10)
DCL VAR(&ERROR) TYPE(CHAR) LEN(10)

DCL VAR(&EVTDATA) TYPE(CHAR) LEN(1024)

Les programmes d’exits

C’est des actions système enregistrées que vous pouvez voir par la commande WRKREGINF, et seules les actions définies dans cette liste sont utilisables.

Pour ajouter un programme c’est soit la commande addexitpgm ou l’option 8 dans wrkreginf.

Le principe , on reçoit un buffer avec les données en cours et on renvoie status pour dire ok ou ko, vous pouvez dire OK systématiquement et traiter ou faire un contrôle d’autorisation applicatif

Exemple sur FTP

PGM PARM (& APPID & OPID & USRPRF & REMOTEIP & REMOTELEN & OPINFO & OPLEN & OK)
DCL & APPID * CHAR 4 /* ID D’APPLICATION, NUM BINAIRE */
DCL & OPID * CHAR 4 /* ID D’OPERATION, NUMERO BINAIRE */
DCL & OPNUM * 4 /* OPERATION ID, UTILISABLE DANS CL */
DCL & USRPRF * CHAR 10 /* PROFIL UTILISATEUR UTILISANT FTP */
DCL & REMOTEIP * CHAR 251 /* ADRESSE IP */
DCL & REMOTELEN * CHAR 4 /* LONGUEUR DU PARAMETRE PRECEDENT */
DCL & OPINFO * CHAR 251 /* INFORMATIONS SPECIFIQUES OP */
DCL & OPLEN * CHAR 4 /* LONGUEUR DU PARAMETRE PRECEDENT */
DCL & OK * CHAR 4 /* SIGNAL DE CONFIRMATION / / seulement utilisateur FTPUSR */
if cond(&USRPRF *ne ‘FTPUSR’) then(do)
chgvar &ok (X’00000001′)
enddo
ENDPGM

pour l’ajouter

ADDEXITPGM EXITPNT(QIBM_QTMF_SVR_LOGON)
FORMAT(TCPL0100) PGMNBR(1) PGM(VOTRELIB/VOTREPGM)

Vous devez arrêter le service FTP pour que cela soit pris en compte
ENDTCPSVR *FTP puis STRTCPSVR

Conclusions

Vous avez plusieurs solutions dans certains cas , et certaines sont plus à jour

les 4 à utiliser aujourd’hui sont
Les triggers pour la base de données, si possible en SQL
Les watchers pour les événements de log systèmes
Les progammes d’exit pour les actions Système, par exemple pour les connexions ODBC
Les dtaq pour gérer des piles de données applicatives

Tous ces programmes sont appelés souvent, ils doivent être donc optimisés et ils ne doivent pas planter pour éviter de bloquer la file !

, 5 astuces pour utiliser SMTP sur l’IBMi

1) Utilisez l’annuaire SMTP

Il faut arrêter d’utiliser la directory SNA, l’objectif est se passer complètement de SNA
c’est le paramètre DIRTYPE, exemple CHGSMTPA DIRTYPE(*SMTP)
Il vous faudra inscrire les utilisateurs à SMTP , addsmtpusr ou wrksmtpusr pour qu’ils puissent envoyer des mails

Sinon vous recevrez un message TCP5090 comme celui ci !

2) Utilisez un user mail en NOREPLY

Créer un utilisateur NOREPLY sans mot de passe
inscrivez le à la directory SMTP
wrksmtpusr ou addsmtpusr

et ensuite envoyer vos mails en les soumettant avec cet utilisateur

exemple :

SBMJOB CMD(SNDSMTPEMM RCP((‘xxx@gaia.fr’)) SUBJECT(‘votre sujet’) NOTE(‘ici texte’)) JOB(MAIL)
USER(NOREPLY)

3) Utiliser du HTML dans le corps du message

paramètre CONTENT(*HTML)

dans la commande SNDSMTPEMM … CONTENT(*HTML)

Vous pouvez alors utiliser des balises HTML dans votre message
Un très bon site ici !
https://openclassrooms.com/fr/courses/1603881-apprenez-a-creer-votre-site-web-avec-html5-et-css3/1608357-memento-des-balises-html

4) Historique des mails

A partir du moment ou vous êtes en DIRTYPE(*SMTP)
Vous n’écrivez plus dans le journal QZMF de QUSRSYS, il est conseillé de passer à JOURNAL(*NO) et ALLMAILMSF(*NO)

pour arrêter MSF qui ne sert plus à rien vous devez supprimer le job à démarrage automatique avec la jobd QZMFEJBD ou vous pouvez changer la jobd et remplacer le STRMSF … par un SNDMSG (‘coucou’) TOUSR(*SYSOPR)

5) Utilisez un sous-système spécifique

Pour des questions d’administration, vous pouvez mettre un sous système spécifique qui permet de mieux gérer les travaux relatives aux mails et qui par défaut sont dans QSYSWRK

CHGSMTPA SBSD(QSYS/QSMTP)

Vous devez arrêter et redémarrer le service pour la prise en compte

Conclusion:

C’est la meilleur solution pour envoyer des mails, il y a des nouveautés à chaque version.

, Comparer 2 fichiers sur l’IBMi

Il y a maintenant un procédure qui permet de comparer 2 tables (COMPARE_FILE), c’est celle qui est utilisée dans ACS.

Voici comment elle s’utilise avec un exemple sur les fichiers AIRPORTS et AIRPORTS2

SELECT * FROM TABLE(QSYS2.COMPARE_FILE(
LIBRARY1=>’FORM01′, FILE1=>’AIRPORTS’,
LIBRARY2=>’FORM01′, FILE2=>’AIRPORTS2′,
COMPARE_ATTRIBUTES=>’NO’,
COMPARE_DATA=>’YES’))

Il y a 2 options de comparaison sur les données et les attributs du fichier

COMPARE_DATA=>’YES’ et COMPARE_ATTRIBUTES=>’YES’ sont les valeurs par défaut
Vous avez alors la liste des rangs (RRN) qui sont différents !


vous pouvez indiquez QUICK si vous voulez juste savoir si vous avez une différence

Vous pouvez indiquez NO si un des 2 paramètres ne vous intéresse pas

Attention vous avez intérêt à faire ça en batch

Donc à mettre dans un fichier résultat

Exemple

create table … as(votre requête) with data

Attention les zones sont des VARGRAPHICs vous devrez les caster pour les utiliser simplement

Exemple :

cast(substr(ATTRIBUTE_NAME , 1 , 132) as char(132)) as ATTRIBUT_NAME