, , 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

, , Passage SQLSTATE en SQL

Depuis la TR4 de la V7R4, vous pouvez passer votre propre SQLSTATE ce qui est très intéressant sur les triggers avants par exemple.
Vous pouvez avoir la vraie raison du refus
C’est un petit pas pour SQL, mais un grand pas pour le développeur SQL

Exemple

Création de la table

CREATE OR REPLACE TABLE ARTICLE (
NOMART CHAR(30) CCSID 297 NOT NULL DEFAULT  » ,
NUMART DECIMAL(6) ,
DESIGN CHAR(25) CCSID 297 NOT NULL DEFAULT  » ,
PRXUNI DECIMAL(6)
)
Insertion d’un article (Je sais, je surfe sur l’actualité du moment)
INSERT INTO ARTICLE VALUES(‘Maillot Benzema’, 19,
‘Maillot Benzema EDF’, 166)

tentative de mise à jour

UPDATE ARTICLE SET PRXUNI = 167 WHERE NUMART = 19

Création d’un trigger de controle
ici on teste que l’utilisateur est bien ‘DBADMIN’ pour pouvoir modifier le tarif

CREATE OR REPLACE TRIGGER ARTICLETRG
BEFORE UPDATE OF PRXUNI ON ARTICLE
FOR EACH ROW
BEGIN ATOMIC
IF CURRENT USER <> ‘DBADMIN’ THEN
SIGNAL SQLSTATE ‘DB999’
SET MESSAGE_TEXT = ‘UTILISATEUR NON AUTORISÉ’;
END IF;
END;

Par SQL

Maintenant dans un programme RPGLE

On va utiliser get diagnostics pour récupérer le SQLTATES et le Message associé

**free
dcl-s MessageText char(45) ;
dcl-s ReturnedSQLState char(5);
exec sql SET OPTION COMMIT = *NONE ;
// test mise à jour trigger
exec sql
UPDATE ARTICLE SET PRXUNI = 167 WHERE NUMART = 19 ;
exec sql
get diagnostics condition 2
:ReturnedSQLState = RETURNED_SQLSTATE ,
:MessageText = MESSAGE_TEXT;
dsply (ReturnedSQLState + ‘ ‘ + MessageText) ;
*inlr = *on ;

Vous lancez le programme

Conclusion :

c’est une nouveauté qui devrait simplifier le contrôle des triggers est donc leur usage.

, , 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

, 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