On utilise de plus en plus java dans les travaux de votre IBMi et on a parfois besoin d’avoir des informations d’exécution

Voici comment connaitre la version de la JVM d’un travail ?

2 solutions simples

==> WRKJWMJOB

Puis 5 puis 1

Ou en utilisant sql services par la vue QSYS2.JVM_INFO

exemple :

select JOB_NAME, JAVA_HOME from qsys2.JVM_INFO

plus d’informations ici

https://www.ibm.com/docs/en/i/7.3?topic=usage-java-system-properties

, Liste de valeurs dans une commande

Vous voulez utiliser dans une commande pour un paramètre une liste de valeur paramétrable

sur la commande de votre paramétre vous avez un paramètre CHOICEPGM pour indiquer votre programme

Ce programme peut être en Rpg ou en CL ou autres, il devra juste respecter un certaine syntaxe sur le paramètre à renvoyer

Voici un petit exemple d’une commande qui permet de passer une bibliothèque de *TEST à *PROD et alternativement

La commande

                           
              CMD        PROMPT('Change Type Lib')                       
 /*  NOM DE FICHIER                                                  */  
              PARM       KWD(BIBLIO) TYPE(*CHAR) LEN(10) MIN(1) +        
                           CHOICE(*PGM) CHOICEPGM(*LIBL/CHGLIBTYP4) +    
                           PROMPT('Nom de la bib')                       

le programme de liste

PGM PARM(&PARM1 &PARM2)                                              
DCL VAR(&PARM1) TYPE(*CHAR) LEN(21)                                  
DCL VAR(&PARM2) TYPE(*CHAR) LEN(2000)                                
  /*--------------------------------------------------------------*/ 
  /* Programme  CHOICEPGM                                         */ 
  /*                                                              */ 
  /* PARM1 :     PREMIER PARAMETRE                                */ 
  /*        1   A   10   NOM DE COMMANDE                          */ 
  /*       11   A   20   NOM DU PARAMETRE DE LA COMMANDE          */ 
  /*       21   A   21   TYPE  (P) LISTE  DE VALEURS    ? ou F4   */ 
  /*                           (C) TEXTE  D'INVITE      F11       */ 
  /*                                                              */ 
  /* PARM2 :     DEUXIEME PARAMETRE                               */ 
  /*   ------>si liste                                            */ 
  /*        1   A    2   NOMBRE DE PARAMETRES TRANSMIS EN BINAIRE */ 
  /*        3   A    4   TAILLE DE LA PREMIERE VALEUR  EN BINAIRE */ 
  /*        5   A    N   PREMIERE VALEUR                          */ 
  /*      N+1   A    N+2 TAILLE DE LA DEUXIEME VALEUR  EN BINAIRE */ 
  /*      N+3   A    M   DEUXIEME VALEUR                          */ 
   /*        ETC...   2000                                         */ 
   /*                                                              */ 
   /*   ------>si texte                                            */ 
   /*        1   A   30   TEXTE A AFFICHER                         */ 
   /*       31   A 2000   INUTILISER                               */ 
   /*                                                              */ 
   /****************************************************************/ 
   /*                                                              */ 
   /*  Déclaration des zones de travail                            */ 
   /*                                                              */ 
   dclf qadspobj                                                      
   DCL        VAR(&FINFICHIER) TYPE(*LGL)                             
   DCL VAR(&BIN) TYPE(*CHAR) LEN(2)                                   
   DCL VAR(&DEC) TYPE(*DEC) LEN(5 0)                                  
   DCL VAR(&SIGN) TYPE(*CHAR) LEN(1)                                  
   DCL VAR(&pos ) TYPE(*dec ) LEN(5)                                  
   DCL VAR(&nbr ) TYPE(*dec ) LEN(10 0)                               
    /*                                                              */
    /* Initialisation de la zone paramètre à retourner              */
   /* Attention elle peut contenir n'importe quoi a l'arrivée      */ 
   /*                                                              */ 
   CHGVAR  VAR(&PARM2) VALUE(' ')                                     
   /*                                                              */ 
   /* Test de la demande  P = liste de paramètres                  */ 
   /*                                                              */ 
               IF         COND(%SST(&PARM1 21 1) *EQ 'P') THEN(DO)    
   /*--------------------------------------------------------------*/ 
   /*                                                              */ 
   /* 1er cas pos 21 = P demande d'une liste de valeurs            */ 
   /*                                                              */ 
   /*--------------------------------------------------------------*/ 
   /*                                                              */ 
   /* Formatage de la variable à retourner                         */ 
   /* Position 1 à 2 en binaire nombre de paramètres de retours    */ 
   /* conversion longueur du paramètre en binaire                  */ 
   /* Position 3  à  4 en binaire longueur de la première valeur   */ 
   /* Position 5  à 14 premiére Valeur à afficher                  */ 
   /* Position 15 à 16 en binaire longueur de la deuxième valeur   */ 

    /* Position 17 à 26 Deuxième Valeur à afficher                  */   
    /* etc ...                                                      */   
    /* xxxxyyyyyyyyyxxyyyyyyyyyxxyyyyyyyyy                          */   
    /* Génération du fichier des bibliothèques  GAIA*               */   
    /*--------------------------------------------------------------*/   
              DSPOBJD    OBJ(QSYS/GAIA*) OBJTYPE(*LIB) OUTPUT(*OUTFILE) +
                           OUTFILE(QTEMP/WADSPOBJ)                       
              OVRDBF     FILE(QADSPOBJ) TOFILE(QTEMP/WADSPOBJ) +         
                           LVLCHK(*NO) SHARE(*YES)                       
              RTVMBRD    FILE(QTEMP/WADSPOBJ) NBRCURRCD(&NBR)            
    /* ecriture nombre de postes */                                      
              chgvar &pos 1                                              
                CHGVAR     VAR(%bin(&BIN)) VALUE(&nbr)                   
                CHGVAR     VAR(%SST(&PARM2 &pos 2)) VALUE(&BIN)          
              chgvar &pos 3                                              
                CHGVAR     VAR(%bin(&BIN)) VALUE(10)                     
   /* Traitement des postes      */                                      
              DOUNTIL    COND((&FINFICHIER) *OR &POS > 1980)             
              rcvf 
             monmsg cpf0864 exec(leave)                              
  /* Ecriture de la longueur du poste */                             
                CHGVAR     VAR(%SST(&PARM2  &pos  2)) VALUE(&BIN)    
             chgvar &pos (&pos + 2)                                  
  /* ecriture du poste                */                             
                CHGVAR     VAR(%SST(&PARM2  &pos  10)) VALUE(&odobnm)
             chgvar &pos (&pos + 10)                                 
             enddo                                                   
             dltovr     FILE(QADSPOBJ)                               
             ENDDO                                                   
 /*--------------------------------------------------------------*/  
 /*                                                              */  
 /* 2ème cas pos 21 = C demande d'un texte                       */  
 /*                                                              */  
 /*--------------------------------------------------------------*/  
             IF         COND(%SST(&PARM1 21 1) *EQ 'C') THEN(DO)     
             CHGVAR     VAR(&PARM2) VALUE('Un nom valide de +        
                          Bibliothèque')                             
             ENDDO                                                   
 ENDPGM 

Le programme de traitement

PGM PARM(&LIB)                                            
/*-----------------------------------------------------*/ 
/* Programme de traitement de la commande              */ 
/* récupération du type et changement                  */ 
/* *PROD  *TEST                                        */ 
/*-----------------------------------------------------*/ 
DCL &LIB *CHAR 10                                         
DCL &TYPE *CHAR 10                                        
             RTVLIBD    LIB(&LIB) TYPE(&TYPE)             
IF COND(&TYPE = '*TEST') THEN(DO)                         
             CHGLIB     LIB(&LIB) TYPE(*PROD)             
ENDDO                                                     
ELSE DO                                                   
             CHGLIB     LIB(&LIB) TYPE(*TEST)             
ENDDO                                                     
ENDPGM   

C’est un exemple simple et facilement transposable, on aurait pu utiliser les vues SQL … pour obtenir la liste de bibliothèque

, , Utilisations des indexs

l’utilisation des index est devenu un enjeux majeur de la bas de données ,

On me pose réguliérement la question sur l’utilisation de ceux ci, je vais essayer de vous éclairer

En DDS/LF RPGLE (par exemple)

Vous connaissez tous cette solution on déclare le fichier LF ou index et on le lis quand on regarde la description de l’objet
vous avez la date de dernière utilisation , bien sur cette information est disponible dans la vue qsys2.object_statistics

En SQL/INDEX SQLRPGLE (par exemple)


Dans ce cas la vous allez lire la table par SELECT et c’est l’optimiseur qui va déterminer que vous avez besoin du chemin d’accès ou pas
attention : ce n’est pas parce que l’index existe qu’il sera utilisé , mais il sera avisé

Pour faire le ménage dans les indexs inutilisés ?

Il vous faudra donc croiser ses éléments avant de faire vos suppressions

rappel

Il y a des procédures dans systools qui permettent d’ajouter des indexs par rapport à des critères ,
c’est la procédure SYSTOOLS.ACT_ON_INDEX_ADVICE
et pour supprimer vous avez la procédures SYSTOOLS.REMOVE_INDEXES (ne supprimera que les index ayants pour nom %RADIX_INDEX% et %EVI_INDEX%
ca peut être brutal de les utiliser comme ca .
Par contre vous pouvez extraire les sources de ces procédures pour voir ce qu’elles font et vous en inspirer …

Vous avez des informations très intéressantes sur le sujet sur le lkdn de Christian Griere (merci à lui)

lien sur les index

https://www.linkedin.com/pulse/vos-tables-db2-i-sont-elles-trop-index%C3%A9es-christian-griere/

autres liens

https://www.linkedin.com/in/christian-griere-6a3828a/recent-activity/posts/

, , Statistiques sur les MTIs

A partir de la TR6 de la V7R4, vous avez une nouvelle vue qui vous permet de visualiser vos MTIs (Maintained Temporary Indexes) c’est des indexs que le système décide de construire temporairement pour optimiser vos requêtes.

C’est ceux la même qui sont perdus à chaque IPL …

Cette nouvelle vue s’appelle MTI_INFO elle est dans QSYS2

plus d’informations ici

https://www.ibm.com/docs/en/i/7.5?topic=services-mti-info-table-function

Rappelle :
Vous pouviez déjà avoir des informations sur les MTIs en interrogeant index advisor, par exemple dans ACS vous avez cet exemple qui vous indique les MTI utilisés depuis le dernière IPL

CONDIDXA étant la vue aggrégée de QSYS2.SYSIXADV

Avec la TR6 de la V7R4 (TR disponible à partir du 24 mai 2022)


Vous pouvez désormais compresser en standard avec l’algorithme *ZLIB dans les commandes SAV*


Bien que un peu vieux, (la première version date de 1995) c’est un algo très fiable et efficace


Pour en savoir plus sur ZLIB https://fr.wikipedia.org/wiki/Zlib

Remarque :

Jusque la on pouvait l’installer en open-source

Envoyer un message avec réponse

Il peut être intéressant d’envoyer un message avec une réponse, pour des traitements occasionnels par exemple .

Voici 2 exemples de code qui font la même chose

exemple en RPG

**free
// Message simple avec réponse
// texte 55 max
dcl-s w_reponse char(1) ;
dsply ‘Voulez-vous continuer ?’ ‘QSYSOPR’ w_reponse;
// traitement de la réponse
if w_reponse = ‘O’;
dsply ‘Oui avec plaisir !’ ‘QSYSOPR’;
else ;
dsply ‘Certainement pas !’ ‘QSYSOPR’ ;
endif ;
*inlr = *on ;

exemple en répondant O

Exemple en CLP

pgm
/* Message simple avec réponse / / */
dcl &w_reponse *char 10
SNDUSRMSG MSG(‘Voulez-vous continuer ?’) +
TOMSGQ(QSYSOPR) MSGRPY(&W_REPONSE)
if cond(&w_reponse = ‘O’) then(do)
SNDUSRMSG MSG(‘Oui avec plaisir !’) msgtype(info) TOMSGQ(QSYSOPR)

enddo

else do

SNDUSRMSG MSG(‘Certainement pas !’) msgtype(info) TOMSGQ(QSYSOPR)
enddo
endpgm

exemple en répondant O

Rappel

C’est n’est pas la meilleur manière pour traiter de l’information, mais ca peut rendre service

, , Droits Navigator for i

il faudra désormais une autorisation explicite pour utiliser Navigator for i

Jusqu’à présent les fonctions usage, QIBM_NAV_SERVICEABILITY et QIBM_NAV_ALL_FUNCTION étaient autorisées par défaut à partir de mai 2022, elles seront interdites par défaut seules les profils ayant les autorisations spéciales *secofr *allobj pourront accéder les autres devront être autorisées nommément.

Plus d’informations ici

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

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

https://www.ibm.com/support/pages/node/6520030#Feb2022

C’est une possibilité de contrôler les requêtes SQL sur le temps d’exécution estimée ou sur la mémoire temporaire , se base sur le plan d’accès créé par l’optimiseur pour votre requête.

C’est la commande CHGQRYA qui permet cette opération
paramètres QRYTIMLMT( ) et QRYSTGLMT( ) pour le temps et la mémoire
Exemple
CHGQRYA JOB(123456/PLB/QPADEV0001) QRYTIMLMT(45)

Vous exécutez votre requête, si elle dépasse 45 secondes un message CPA4259 qui nécessite une réponse est envoyé au travail
Si vous répondez I ca continue,

 La requête excède la limite de durée ou de mémoire définie (C I)

? I

C si vous voulez arrêter la requête

La requête dépasse la limite de durée ou de mémoire définie.
? C
SQL query exceeds specified limit or threshold.

Vous pouvez estimer le temps d’exécution d’une requête

Mettre le temps maxi à zéro
CHGQRYA QRYTIMLMT(0)
Lancer la requêtes
Retrouvez le message CPA4259 et répondez C
Si vous faites sur le message vous avez le temps d’exécution estimée
ID message . . . . . . : CPA4259
Date d’envoi . . . . . : 26/04/22 Heure d’envoi . . . . : 14:23:33

Message . . . . : La requête excède la limite de durée ou de mémoire définie
(C I)

Cause . . . . . : La requête de base de données qui allait démarrer a une
durée d’exécution estimée à 12, ce qui excède la limite indiquée 0, ou son
utilisation de mémoire temporaire de 1 dépasse la limite spécifiée

  1. Les limites de durée de requête et de mémoire temporaire sont
    définies via la commande CL CHGQRYA.

remettre la valeur par défaut
CHGQRYA QRYTIMLMT(*SYSVAL)

remarque

Attention si vous avez de requêtes sous forme de curseur dans un sqlrpgle par exemple

Le traitement ne s’arrête pas , mais votre open cursor va recevoir un SQLCODE -666, si vous avez des traitements dépendants ca peut être gênant. il est donc conseillé de rajouter le contrôle derrière cette opération

exemple

if sqlcode = -666 ;
dsply ‘Estimation requête excessive’ ;
*inlr = *on ;
return;
Endif;

Pour mettre une réponse automatique C


Utiliser la table de réponse de travaux

par exemple
ADDRPYLE SEQNBR(56) MSGID(CPA4259) CMPDTA(PLB 51) RPY(C)
puis indiquer que le travail est en réponse auto
CHGJOB INQMSGRPY(*SYSRPYL)

Vous pouvez également indiquer quel fichier qaqqini vous voulez utiliser

paramètre CHGQRYA QRYOPTLIB(PLB)

Vous devez indiquer la bibliothèque ou ce trouve votre fichier d’options

plus d’informations ici


https://www.ibm.com/docs/en/i/7.4?topic=governor-how-use

, , Transformation LF en index

Pourquoi transformer des DDS en SQL?

Une des raisons est que les index peuvent être beaucoup plus performants que les LF quand le moteur SQL les utilise.

Rappel
Pour transformer un PF en table

Vous devez extraire le source en utilisant l’API QSQGNDDL
Le plus simple est de passer par ACS
En faisant génération instruction SQL

Vous obtenez le source SQL qu’il aurait fallu pour générer cette table.


Attention tout n’est pas traduit (exemple un PF sans clé unique)

Pour transformer un LF en index sur nom par exemple

Si vous utilisez ACS, votre index est considéré comme une vue et si vous faites l’opération de génération SQL vous obtenez un source qui ne va pas vous servir à grand chose.
Remarque, par contre si vous regardez par Visual Explain vous voyez bien que le moteur utilise le PF comme un index.

Si vous utilisez la procédure de QSYS2.GENERATE_SQL, même problème.

.

Si vous lui indiquez index, il ne trouve pas l’objet SQL

CALL QSYS2.GENERATE_SQL(‘AALF’, ‘GDATA’, ‘INDEX’,
‘QSQLSRC’, ‘GDATA’, ‘AALF’,
CREATE_OR_REPLACE_OPTION => ‘1’,
CONSTRAINT_OPTION => ‘2’);

La solution est donc passer directement par l’API système QSQGNDDL.

Pour vous aider, on a fait une commande RTVSQLSRC que vous pouvez trouver ici

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

et là vous pouvez forcer le type INDEX

RTVSQLSRC FILE(GDATA/AALF) SRCFILE(GDATA/QSQLSRC) TYPSQL(INDEX)

et là vous obtenez le source qui va bien

Même remarque que pour les PF (tout ne se traduit pas exemple LF avec sélection)

Une fois que vous avez le source il vous suffit alors de rejouer le script SQL.

Remarque :

Vous ne pouvez pas faire un create or replace , puisque SQL continue à voir le LF comme une vue.
Vous devez donc le supprimer avant le recréer.

Compléments apportés par Birgitta merci à elle

Il y a 2 options en GENERATE_SQL et le ACS wizard avec lesquelles on peut transformer LFs en index.

https://www.ibm.com/docs/en/i/7.4?topic=services-generate-sql-procedure


Out of the GENERATE_SQL documentation:
INDEX_INSTEAD_OF_VIEW – option:
The index instead of view option specifies whether a CREATE INDEX or CREATE VIEW statement will be generated for a DDS-created keyed logical file. The valid values are:

0 – A CREATE VIEW statement will be generated.
1 – A CREATE INDEX statement will be generated that matches the index for a DDS-created keyed logical file.

ADDITONAL_INDEX_OPTION:
The additional index option specifies whether additional CREATE INDEX statements will be generated for DDS-created keyed physical or logical files. The valid values are:

0 – Additional CREATE INDEX statements will not be generated.
1 – An additional CREATE INDEX statement will be generated that matches the index for a DDS-created keyed physical file. If the physical file has a PRIMARY KEY constraint, a CREATE INDEX statement is not generated.
An additional CREATE INDEX statement will be generated that matches the index for a DDS-created keyed logical file. If a value of ‘1’ is specified for the index instead of view option, an additional CREATE INDEX statement is not generated. Additional CREATE INDEX statements will also be generated that match the join indexes of a DDS-created join logical file.