, 5 choses à savoir sur le CPYF

Vous voulez copier un fichier vers un autre, une des alternatives est d’utiliser SQL, en utilisant une instruction du genre insert into ficcible select * from ficsource.
Il existe d’autres méthodes que les plus anciens connaissent bien, mais les nouveaux un peu moins.
C’est la commande CPYF voici quelques utilisation à connaître

1) Les sélections

Sélection d’un nombre d’enregistrement
Paramètres
FROMRCD
TORCD
exemple les 100 premiers
FROMRCD(1)
TORCD(100)

Sélection sur des valeurs de clé
FROMKEY
TOKEY
exemple les clés de 0001 à 0002
FROMKEY(1 (0001))
TOKEY(1 (00002))

Sélection sur des caractères d’un format
INCCHR RCD Exemple les enregs qui OUI en position 15 INCCHAR(RCD 15 *EQ ‘OUI’)

Sélection des avec des relations
INCREL
Exemple les enregistrements valides et avec une date de référence > ‘20200101’
INCREL((*IF VALIDE *EQ ‘OUI’) (*AND DATEREF *GT ‘20200101’))

2) Les performances

La plupart du temps un CPYF est plus rapide qu’une copie par SQL

Quand on copie un fichier qui a des clés, pour améliorer les performances
on peut indiquer, FROMRCD(1) au lieu de FROMRCD(*START) , la copie se fera sans tenir compte de l’index, et le gain est d’environ la moitié.

3) Les ajustements de zones


Paramètre FMTOPT
utilisez les 2 paramètres suivants pour que vos nouvelles zones soient initialisées et que celle qui ont changé soient recadrées
FMTOPT(*MAP *DROP)

4) Les messages d’erreur


Vous devez monitorer, votre commande CPYF, CPF2800 CPF2900 CPF3100
Avant de copier, vérifier si votre fichier source contient des enregistrements
DCL &nbr *dec 10
RTVMBRD SOURCE NBRRCD(&nbr)
if cond(&nbr *gt 0) then(do)
cpyf …
enddo

5) Formater à l’exécution


Pour améliorer le paramétrage et l’administration vous pouvez construire la commande CPYF dynamiquement

dcl &cmd *char 1024

chgvar &cmd (‘cpyf *bcat ……)
call qcmdexc (&cmd %len(&cmd))

Conclusion :

Le CPYF permet de nombreuses formes de copies et son usage est indispensable !

, , , 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 petites astuces pour améliorer votre base de données

1) Vous désirez mettre des noms longs .

Vous avez un fichier pf, et pour les gens qui font des requetes dessus vous voulez mettre des noms plus signicatif

exemple remplacer num234 par numero_de_client

Vous ne voulez pas ou vous pas migrer vers une base en SQL , voila comment faire

Cette opération ne peut pas être faite en SQL
En effet ALTER TABLE FICHIER1 ALTER COLUMN ne permet pas de changer le nom de la colonne

C’est le mot clé Alias qui permet ca

Fichier avant

A R FICHIER1F
A*
A NUMCLI 5 0 COLHDG(‘Numéro’ ‘Client’)
A NOMCLI 30 COLHDG(‘Nom ‘ ‘Client’)
A PRECLI 30 COLHDG(‘Prénom’ ‘Client’)

Vous pouvez mettre des noms longs

fichier après, on ajoute les alias

A R FICHIER1F
A*
A NUMCLI 5 0 COLHDG(‘Numéro’ ‘Client’)
A ALIAS(NUMERO_CLIENT)
A NOMCLI 30 COLHDG(‘Nom ‘ ‘Client’)
A ALIAS(NOM_CLIENT)
A PRECLI 30 COLHDG(‘Prénom’ ‘Client’)
A ALIAS(PRENOM_CLIENT)

Pour ne pas perdre vos données vous pouvez faire un change pf

CHGPF FILE(GDATA/FICHIER1) SRCFILE(GDATA/QDDSSRC) SRCMBR(FICHIER1)

Cette opération ne change pas le niveau de format , pas de recompile de votre application

vous devrez avoir le source sur votre machine de prod pour faire un CHGPF

Si vous n’avez pas le source mais que vous voulez préparer les données pour de la BI par exemple
vous pouvez faire des vues qui seront utilisées à la place de vos PF !

Exemple

CREATE VIEW fichier_client AS
SELECT nomcli as nom_client,
numcli as numero_client,
precli as prenom_client
FROM fichier1

2) Vous voulez ajouter une zone à notre pf

L’opération peut se faire cette fois directement par SQL, même sur un PF

Exemple, vous voulez ajouter une zone mail à votre fichier

ALTER TABLE FICHIER1 ADD COLUMN MAIL_CLIENT FOR COLUMN MAIL
CHARACTER ( 50) CCSID 1147 NOT NULL WITH DEFAULT

Vous ne perdez pas les données, ni les fichiers qui pointent dessus
Mais attention comme en DDS vous changer le niveau de format donc vos programmes doivent être recompilés ou vous devez indiquer lvlchk(*no) sur vos fichiers (analyse à faire)
Vous restez en format DDS, vous ne pourrez pas ajouter tous les types de données
Attention il faudra reporter la zone dans votre DDS pour être cohérent

3) Contrôlez les données de vos fichiers

Si vous avez des fichiers PF, vous pouvez avoir des données erronées, vous pouvez maintenant simplement contrôler la validité de vos données par une fonction table, systools.validate_data !

select *
from table (
systools.validate_data(
library_name => ‘votrebib’, file_name => ‘FICHIER1’,
member_name => ‘*LAST’) )

Ça vous permettra d’avoir la liste des enregistrements qui ont des erreurs de données, ça peut être intéressant de le faire de temps en temps sur les données sensibles de votre base.

4) Supprimer définitivement les enregistrements effacés

Quand vous supprimez vos données elles ne sont pas réellement supprimés elles sont juste flaguées
Pour les supprimer vous devez faire un RGZPFM de votre table qui supprimera réellement les enregistrements et qui reconstruira les indexes .
Commencer par le faire sur les tables qui ont le plus d’enregistrements supprimés

5) Contrôler qu’il ne vous manque pas d’index

Un des principaux axe pour améliorer les performances de votre base de données est souvent d’ajouter des index manquants.

Pour connaitre les index à analyser, vous avez une table qui s’appelle QSYS2.SYSIXADV qui vous propose des suggestions d’index

Vous pouvez ajouter les index qui sont souvent et régulièrement demandés.

Vous pouvez également voir ces suggestions sur ACS.

, 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

, Analyser les homedir de vos utilisateurs

Vous utilisez de plus en plus les fichiers dans l’IFS pour échanger vos csv , PDF etc … ou par des connexions qui utilisent l’open source.

.

Ces chiffres sont ceux , constatés sur les clients du groupe Gaia Volubis et incluent la partie complètes des fichiers de l’IFS (/home et le reste).

Par défaut quand vous créer un profil par la commande CRTUSRPRF, vous avez le paramètre HOMEDIR( *USRPRF) ce qui indique un répertoire par défaut /home/USRPRF.

Le Homedir correspond au répertoire par défaut comme la *Curlib du coté de QSYS.LIB.

Attention il n’y a pas de contrôle d’existence et si le répertoire n’existe pas l’utilisateur va travailler à la racine ce qui peut créer des fichiers indésirables à la racine de votre système, et qui contribue à une désorganisation de l’IFS !

De même si certains utilisateurs ont un répertoire par défaut différent de cela peut complexifier vos procédures de ménage. Les répertoires homedir de vos users devant servir le plus souvent à des échanges et non pas du stockage.

Voici quelques requêtes pour vous aider à analyser cela

Liste des répertoires utilisateurs avec leur répertoire théorique

Select AUTHORIZATION_NAME as user_profile, home_directory from QSYS2.USER_INFO

Liste des utilisateurs avec leur répertoire associé existant

create table exploit.usr_dir as(
WITH TEMP_A AS(
SELECT cast(substr(PATH_NAME , 1 , 132) as char(132)) as path_name, ALLOCATED_SIZE
FROM TABLE(IFS_OBJECT_STATISTICS(
START_PATH_NAME => ‘/HOME’ ,
OBJECT_TYPE_LIST => ‘*ALLDIR’))
where
LOCATE_IN_STRING(path_name, ‘/’, 1 , 2) > 1
)
select * from temp_a join QSYS2.USER_INFO on ucase(‘/home/’ concat authorization_name) = ucase(path_name)
) with data

dans ce cas je crée un fichier temporaire, mais vous pouvez le faire en une seule requête

Voici donc 2 principales erreurs à surveiller

Liste des utilisateurs avec un homedir qui n’est pas dans /home

select * from QSYS2.USER_INFO
where ucase(home_directory) not like(‘/HOME/%’)

Liste des utilisateurs avec une homedir inexistante

select a.AUTHORIZATION_NAME, a.HOME_DIRECTORY from QSYS2.USER_INFO as a exception join exploit.usr_dir as b on ucase(trim(a.Home_directory)) = ucase(trim(b.Path_name))

Liste des partages avec sur /home

SELECT SERVER_SHARE_NAME, PATH_NAME, PERMISSIONS FROM QSYS2.SERVER_SHARE_INFO
where ucase(path_name) like(‘/HOME%’) and SHARE_TYPE = ‘FILE’

Vous devez en avoir un seul avec *RW

Rappel , par contre vous ne devez pas partager la racine pour contrôler passez la requête suivante,

SELECT SERVER_SHARE_NAME, PATH_NAME, PERMISSIONS FROM QSYS2.SERVER_SHARE_INFO
where path_name = ‘/’

Remarque :

Dans cette partie de l’ifs pas de différentiation majuscule minuscule

Si vous avez beaucoup de fichiers à la racine, regardez les propriétaires, vous avez surement un homedir mal paramétré.

Rappel, vous ne devez pas partager la racine

, , Rechercher dans l’IFS de votre IBMi

Il peut vous arriver de vouloir rechercher une chaine de caractères dans votre IFS voici comment vous pouvez faire en utilisant SQL service .

1) Recherche d’un nom fichier sur une chaine

SELECT cast(substr(PATH_NAME , 1 , 132) as char(132)) as PATH_NAME
FROM TABLE(IFS_OBJECT_STATISTICS(
START_PATH_NAME => ‘/HOME/PLB’ ,
OBJECT_TYPE_LIST => ‘*ALLSTMF’))
where ucase(PATH_NAME) like (‘%PRO%’)

Ici, recherche PRO dans le nom du fichier du répertoire /HOME/PLB

2) Recherche d’une chaine dans les fichiers

Création d’un fichier résultat !

CREATE OR REPLACE TABLE RETURN_TABLE
(STMF_NAME char(100),
LINE_NUMBER decimal(5 , 0),
LINE varchar(132))

Recherche de la chaine dans tous les fichiers

begin
for
SELECT PATH_NAME as IFS_PATH_NAME
FROM TABLE(IFS_OBJECT_STATISTICS(
START_PATH_NAME => ‘/HOME/PLB’ ,
OBJECT_TYPE_LIST => ‘*ALLSTMF’))
do
INSERT INTO RETURN_TABLE
SELECT IFS_PATH_NAME ,
LINE_NUMBER ,
cast(substr(LINE , 1 , 132) as char(132))
FROM TABLE(IFS_READ(
PATH_NAME => IFS_PATH_NAME))
WHERE UPPER(LINE) like ‘%’ concat ‘PRO’ concat ‘%’ ;

end for;
end

Ici, recherche PRO dans les fichiers du répertoire /HOME/PLB

Attention

Ces recherches sont très consommatrices elles doivent être soumises en batch

Conclusions :


Ça peut vous aidez dans vos recherches, mais attention au nombre de fichiers à scanner.
Si vous êtes amené à faire régulièrement ce type de recherche, préférer la mise en œuvre de OMNIFIND

Si vous voulez l’exemple en fonction table il est ici :

https://github.com/Plberthoin/PLB/tree/master/GTOOLS/SQL

, Création d’un référentiel de vos sources

Cette astuce ne remplace pas un outil du marché qui vous offrira beaucoup plus d’opportunités, en terme d’analyses et d’interactions avec d’autres outils de développements de la plateforme IBM i.

Mais il est possible que vous n’ayez pas la chance de posséder un de ces outils, et voici une méthode qui va vous permettre basiquement de trouver ou est utilisée une zone par exemple si vous désirez changer ses attributs.

La méthode utilisée dans notre cas consiste à créer un fichier avec l’intégralité de vos lignes sources, que vous pouvez faire générer chaque nuit par exemple

Pour cela il va falloir d’abord faire liste des membres sources de votre machine

Creation de la table pour votre liste

CREATE TABLE LSTMBRsrc (
LIB CHAR(10) CCSID 297 NOT NULL ,
FILE CHAR(10) CCSID 297 NOT NULL ,
MBR CHAR(10) CCSID 297 NOT NULL ,
TYP CHAR(10) CCSID 297 DEFAULT NULL )

Remplissage de la table, vous pouvez affiner en éliminant des bibliothèques inutilisées.

ici on utilise le fichier de référence du système SYSPARTITIONSTAT en SQL une partition = un membre

insert into lstmbrsrc
SELECT
substr(TABLE_SCHEMA, 1, 10) as lib,
substr(TABLE_NAME, 1, 10) as file,
substr(TABLE_PARTITION, 1, 10) as mbr,
source_type
FROM SYSPARTITIONSTAT WHERE substr(TABLE_SCHEMA, 1, 1) <>  »Q » and +
not source_type isnull and NUMBER_ROWS > 0′)

Création de la table résultat

qui aura les informations du sources (srcdta, srcseq, srcdta et du fichier srclib, srcfil, srcmbr, srctyp) , vous pouvez ajouter d’autre zones sur les dates par exemple .

CREATE TABLE LSTSRC (
SRCLIB CHAR(10) CCSID 1147 NOT NULL DEFAULT  » ,
SRCFIL CHAR(10) CCSID 1147 NOT NULL DEFAULT  » ,
SRCMBR CHAR(10) CCSID 1147 NOT NULL DEFAULT  » ,
SRCTYP CHAR(10) CCSID 1147 NOT NULL DEFAULT  » ,
SRCSEQ NUMERIC(6, 2) NOT NULL DEFAULT 0 ,
SRCDTA CHAR(100) CCSID 1147 NOT NULL DEFAULT  » ,
SRCDAT NUMERIC(6, 0) NOT NULL DEFAULT 0 )

Maintenant, il faut la remplir en lisant le fichiers des membres

Voici en clp un exemple de code, à faire pour chaque membre

Création de l’alias (nécessaire à SQL pour accéder aux données d’un membre)

CHGVAR &REQUETE ( +
‘CREATE ALIAS QTEMP/WLSTMBR FOR’ *BCAT &LIB *TCAT ‘/’ *TCAT &FILE +
*BCAT ‘(‘ *TCAT &MBR *TCAT ‘)’)
RUNSQL SQL(&REQUETE) COMMIT(*NONE)
monmsg sql0000

Remplissage du fichier avec les informations du membre

CHGVAR &REQUETE +
(‘INSERT INTO LSTSRC SELECT  »’ *TCAT &LIB *TCAT  »’ ,  »’ *TCAT +
&FILe *TCAT  »’ ,  »’ *TCAT +
&MBR *TCAT  »’ ,  »’ *TCAT +
&typ *TCAT  »’ , ‘ BCAT + ‘SRCSEQ , SRCDTA , SRCDAT FROM WLSTMBR’) RUNSQL SQL(&REQUETE) COMMIT(NONE)
monmsg sql0000

Suppression de l’alias

CHGVAR &REQUETE ( +
‘DROP ALIAS QTEMP/WLSTMBR’)
RUNSQL SQL(&REQUETE) COMMIT(*NONE)
monmsg sql0000

Ce traitement est un peu long , il est fréquent d’avoir plusieurs millions d’enregistrements dans votre fichier résultat, attention donc aussi à la place disponible sur votre partition !

Maintenant vous pouvez rechercher une chaine de caractère dans votre fichier exemple un NOM de ZONE.

Dans notre exemple recherche *LDA en majuscule ou minuscule avec création d’un fichier source ici LISTE

create table QTEMP/LISTE as (
SELECT * FROM
lstsrc
WHERE SRCDTA like(‘%*LDA%’)
) with data

Conclusion :

Pensez à faire du ménage dans tout les sources qui ne servent plus.
Si vous n’avez pas les sources vous ne pouvez rien faire mais c’est vrai dans tous les cas.
En cas d’analyse d’impacts vous devrez croiser avec une analyse sur les objets , exemple sortie de dsppgmref
Si vous devez faire de gros changements à effectuer, il est opportun de s’équiper d’un produit qui fera tout ca pour vous .
En attendant d’avoir tout dans l’IFS et de pouvoir tout mettre sous GIT … , c’est le monde d’après .

, , Exécuter une action sur une liste SQL service

Vous avez tous compris qu’une grande partie de l’administration de vos IBMi se fera par SQL service.

Pour faire des contrôles, l’accès aux vues est suffisante.

Par exemple, le contrôle du nombre de pages dans une OUTQ :

SELECT sum(TOTAL_PAGES)
FROM QSYS2.OUTPUT_QUEUE_ENTRIES_BASIC
where OUTPUT_QUEUE_LIBRARY_NAME = ‘SRCEXPL’ and OUTPUT_QUEUE_NAME = ‘VOTREOUTQ’

Mais pour agir c’est plus compliqué, dans certains cas il existe des procédures pour les DTAQ par exemple.

Mais la plus part du temps, vous devrez passer par une commande système dans ce cas en SQL ; vous pouvez utiliser la procédure cataloguée QCMDEXC.

Elle fonctionne comme l’api du même nom.

Exemple :

Pour épurer l’OUTQ QEZJOBLOG

Call qcmdexc(‘CLROUTQ QEZJOBLOG’)

Mais comment faire pour agir sur une liste sans faire un programme ou une procédure qui lirait un curseur ?

L’astuce est d’utiliser un For et dans le select de générer directement la commande à exécuter

Voici un exemple de script qui déplace les spools des OUTQs, commençant par ACT en mettant en référence utilisateur l’OUTQ d’origine.

les zones SPOOLNAME, JOBNAME, FILENUM, OUTQ_QUEUE_NAME proviennent de la vue.

begin
for
SELECT ‘ chgsplfa FILE(‘ concat SPOOLNAME concat ‘) JOB(‘ concat JOB_NAME concat ‘) SPLNBR(‘ concat char(FILENUM) concat ‘) outq(Votreoutq) save(*yes) usrdta( »’ concat OUTPUT_QUEUE_NAME concat  »’)’ as chgspl
FROM QSYS2.OUTPUT_QUEUE_ENTRIES_BASIC
where OUTPUT_QUEUE_LIBRARY_NAME = ‘Votrelib’ and OUTPUT_QUEUE_NAME like(‘ACT%’)
do
call qcmdexc(CHGSPL);
end for;
end

Conclusions :

Cette solution est souvent utilisée par exemple avec la fonction table OBJECT_STATISTICS.

Exemple :

pour faire la liste des fichiers SAVF

SELECT objname, objlib, ifnull(objtext, ‘ ‘) as objtext
FROM TABLE (QSYS2.OBJECT_STATISTICS(‘ALL’,’FILE’) ) AS X
WHERE OBJATTRIBUTE = ‘SAVF’

La seule limite est qu’il est un peu plus compliqué pour gérer les erreurs sur le qcmdexc …

Bien sûr pour la bible rendez vous sur la page de Scott Forstie

, 5 choses à connaitre sur la notion de membre

1) Qu’est ce qu’un membre ?
Un membre est une notion purement IBM i, il sert à cloisonner les données dans un fichier, l’usage le plus connu c’est les fichiers sources où chaque objet est défini dans un membre.
mais on peut également utiliser cette notion pour des fichiers de données , exemple un fichier client avec un membre par régions pour cloisonner les informations.

Pour choisir le membre, on utilisait la commande ovrdbf
OVRDBF FILE(VOTREFIC) MBR(VOTREMEMBRE) quand vous aviez fini, vous faisiez un DLTOVR

Attention un LF peut pointer sur les données de pluseiurs membre du PF, c’est même la valeur par défaut de la commande,
CRTLF … DTAMBRS(*ALL)

2) Pourquoi utiliser la commande DSPPFM
Parce que c’est la seule commande qui montre les données brutes dans l’ordre réel, en effet SQL pourra faire des modifications de présentation, voire indiquer des erreurs de lectures.
Les touches de fonction F10 et F11 permettent de voir les données en hexadécimal.

3) Pourquoi réorganiser les membres des fichiers.
Quand on supprime un enregistrement dans un fichier donc dans un membre, cet enregistrement est juste tagué comme étant inutilisable.
il y a 2 cas:

  • en DDS, les fichiers sont créés avec le paramètre par défaut reusedlt(no) => un nouvel enregistrement est ajouté à la fin.
  • en SQL, les fichiers sont créés avec le paramètre par défaut reusedlt(yes) => un nouvel enregistrement est ajouté sur la place d’un enregistrement supprimé.

En SQL, on a donc besoin de moins de RGZPFM et surtout, si on a sensiblement le même nombre de créations et de suppressions.

4) Executer une requête sql sur un membre d’un fichier physique

Par défaut SQL s’exécute sur le premier membre crée en effet, il considère qu’il n’y a qu’un membre,
en effet un create table ne permet qu’un membre.

Si vous voulez lire un membre particulier sur un fichier physique multi-membres par SQL, vous devez faire un create alias
exemple :
CREATE ALIAS BIBLIO/NOMALIAS FOR BIBLIO/FICHIER (NOMMEMBRE)

vous utilisez désormais votre alias comme un fichier ou une vue

Select * from BIBLIO/NOMALIAS

Vous pouvez supprimer votre alias
DROP ALIAS BIBLIO/NOMALIAS

5) Avoir des informations sur les membres
il y a 2 solutions, de manière historique en lançant la commande dspfd … TYPE(*MBRLIST)
ou avoir des informations par SQL (on parle de partition …)
Vous avez une vue dans qsys2 qui s’appelle SYSPARTITIONSTAT et qui permet de voir ces informations.

Conclusion :
Utiliser les membres n’est pas le sens de l’histoire
En SQL on utilise des fichiers mono-membre
Pour les sources préférer L’IFS qui vous permettra d’utiliser des outils comme GIT
Mais il serait étonnant que vous n’en rencontriez pas, il faut donc comprendre comment ça marche.

, , Comment administrer vos sessions NODEJS

Rappel

Nodejs est disponible en open source sur l’IBMi, vous pouvez l’installer à partir de l’option de ACS :
Outils / Gestion des modules open source

Pour savoir si le produit est installé sur votre machine vous devez taper :
/QOpenSys/pkgs/bin/node -v
Si NODEJS est installé vous aurez la version installée qui s’affiche

Pour lancer une session nodejs, vous devez indiquer l’adresse ip et le port d’écoute
webserver.listen(port, ip)

L’astuce qui va vous simplifier la vie c’est de passer le port en paramètre, ce qui vous permettra de lancer plusieurs sessions du même script.

Pour lancer votre session Nodejs avec votre script vous devez passer la commande suivante :

/QOpenSys/pkgs/bin/node votrescripte.js votreport

Pour réaliser ceci, un script Nodejs reçoit un tableau d’argument
0 = node
1 = votre script
2 = premier paramètre dans votre cas le port

Pour le récupérer dans votre script vous devez indiquer

port = process.argv[2] ;

Vous pouvez lancer autant de scripts que vous le voulez en gérant le port à chaque lancement !

Quand vous soumettez une session nodejs, il lance plusieurs travaux

NODE2999 QSECOFR BATCH ACTIF
QP0ZSPWT QSECOFR BATCHI ACTIF
QZSHSH QSECOFR BATCHI ACTIF

Le plus simple serait donc de tout isoler dans un sous système pour gérer, les sessions, le démarrage et l’arrêt de l’environnement

Nous avons réalisé une console qui permet de gérer tous ces aspects, vous pouvez trouver le source de cette console à l’adresse suivante :

https://github.com/Plberthoin/PLB/tree/master/GNODE

Avec SQL Service vous pouvez administrer ces sessions

SELECT
* FROM TABLE(QSYS2.ACTIVE_JOB_INFO( JOB_NAME_FILTER => ‘xxx*’,
SUBSYSTEM_LIST_FILTER => ‘yyy’)) X
where job_type = ‘SBS’

xxx racine des travaux soumis

yyy sous-système de votre environnement

Ci dessous quelques site web qui peuvent vous aider .

https://www.ibm.com/developerworks/ibmi/library/i-running-node-js-web-app-trs/index.html

https://www.ibm.com/support/pages/node/1127733

https://developer.ibm.com/components/ibm-i/articles/i-native-js-app-ibmi-with-nodejs/