, , , , Verrouiller vos sources pour VSCODE

Une des difficultés, quand on développe avec VSCE sur IBMi ,
C’est que si on est 2 deux à modifier le même source, c’est le dernier qui a raison avec perte de modification du premier même s’il a sauvegardé

Voici comment on peut améliorer les choses.
On va créer un fichier base de données qui liste les sources qui sont en cours de maintenance, un peu comme un ALM.

Avec GIT on peut arriver à des mécanismes identiques, et surtout, il faut commencer à mettre vos sources dans l’IFS directement

Voila comment, vous pouvez faire pour améliorer les choses

CREATE TABLE DB_OPENLCK (FICHIER CHAR ( 10) NOT NULL WITH
DEFAULT, BIBLIO CHAR ( 10) NOT NULL WITH DEFAULT, MEMBRE CHAR ( 10)
NOT NULL WITH DEFAULT, PARTAGE CHAR ( 3) NOT NULL WITH DEFAULT,
PUSER CHAR ( 10) NOT NULL WITH DEFAULT, PDATE DATE NOT NULL WITH
DEFAULT, PTIME TIME NOT NULL WITH DEFAULT)

Pour ajouter un source à verrouiller

INSERT INTO DB_OPENLCK VALUES(‘QRPGLESRC’, ‘GDATA’, ‘AAAA’,
‘NON’, ‘PLB’, current date, current time)

Et parmi les programmes d’exit il en a un qui va nous permettre de mettre en œuvre ce contrôle
C’est le QIBM_QDB_OPEN

On va donc écrire un programme, ici en SQLRPGLE

**free
//
// ce programme permet d'éviter de travailler à 2 sur un même source
//
Dcl-Pi *N;
  DS_parm          likeds(ds_parm_t) ;
  reponse          int(10);
End-Pi;
// dsprogramme
 dcl-ds *N PSDS ;
  nom_du_pgm CHAR(10) POS(1);
  init_user  CHAR(10) POS(254);
  enc_user  CHAR(10) POS(358);
End-ds ;
// ds format  DBOP0100
Dcl-DS ds_parm_t qualified template ;
  taille_entete  Int(10);
  format         Char(8);
  offset_liste   Int(10);
  nbr_fichiers   Int(10);
  taille_liste   Int(10);
  job            Char(10);
  profil         Char(10);
  jobnbr         Char(6);
  cur_profil     Char(10);
  reste          Char(1024);
End-DS;
  // liste des fichiers dans notre cas un seul
Dcl-DS liste  ;
  fichier       Char(10);
  biblio        Char(10);
  membre        Char(10);
  filler         Char(2);
  typefichier    Int(10);
  sous_jacent    Int(10);
  access         Char(4);
End-DS;
// variable de travail
Dcl-S partage      char(4);
Dcl-S puser      char(10);

ds_parm.offset_liste += 1;
dsply   enc_user ;

  liste = %subst(ds_parm : ds_parm.offset_liste :
  ds_parm.taille_liste);

    ds_parm.offset_liste += ds_parm.taille_liste;
 // lecture des informations dans le fichier de verrouillage explicite
 // le verrouillage est donc par utilisateur
   exec sql
   SELECT PARTAGE, PUSER into :partage , :puser
      FROM DB_OPENLCK WHERE FICHIER = :FICHIER and BIBLIO
             = :BIBLIO and MEMBRE = :MEMBRE  ;
   //
   // La régle mise en oeuvre ici
   // on autorise
   // si même utilisateur
   // si non trouvé en modification
   // Si on on a dit partage à oui
   //
  if (sqlcode = 100  or partage = 'OUI' or puser = enc_user) ;
    reponse = 1 ;
  else ;
    reponse = 0 ;
  endif ;
  // fin de programme

*inlr = *on; 

ici notre règle est la suivante
on autorise
Si le source n’est pas présent dans le fichier
Si l’utilisateur est le même que celui en cours
Si on a accepté le partage et donc le risque

Pour ajouter votre pgm exit

SYSTEM/ADDEXITPGM EXITPNT(QIBM_QDB_OPEN)
FORMAT(DBOP0100)
PGMNBR(1)
PGM(GDATA/OPENSRC)
REPLACE(*NO)

Quand on essaye d’accéder par VSCDE à notre source

Remarque


Le contrôle marche aussi avec RDI
Il marche également pour SEU, parfois on préfère un contrôle spécifique SEU, vous devrez utiliser le programme d’exit
QIBM_QSU_ALW_EDIT en utilisant le même fichier par exemple !

 **free                                                                                       
 //                                                                                           
 // Ce programme eviter de travailler à 2 sur un même source                                 
 //                                                                                           
 Dcl-Pi *N;                                                                                   
   biblio     char(10);                                                                       
   fichier    char(10);                                                                       
   membre     char(10);                                                                       
   reponse    char(1);                                                                        
 End-Pi;                                                                                      
 // dsprogramme                                                                               
  dcl-ds *N PSDS ;                                                                            
   nom_du_pgm CHAR(10) POS(1);                                                                
   init_user  CHAR(10) POS(254);                                                              
   enc_user  CHAR(10) POS(358);                                                               
 End-ds ;                                                                                     
                                                                                              
 Dcl-S partage      char(4);                                                                  
 Dcl-S puser      char(10); 
                                                                           
 // lecture des informations dans le fichier de verrouillage explicite     
 // le verrouillage est donc par utilisateur                               
   exec sql                                                               
   SELECT PARTAGE, PUSER into :partage , :puser                           
      FROM DB_OPENLCK WHERE FICHIER = :FICHIER and BIBLIO                 
             = :BIBLIO and MEMBRE = :MEMBRE  ;                            
   //                                                                     
   // La règle mise en œuvre ici                                         
   // on autorise                                                         
   // si même utilisateur                                                 
   // si non trouvé en modification                                       
   // Si on on adit partage à oui                                         
   //                                                                     
  if (sqlcode = 100  or partage = 'OUI' or puser = enc_user) ;            
    reponse = '1' ;                                                       
  else ;                                                                  
    reponse = '0' ;                                                       
  endif ;     
  // fin de programme    
                         
*inlr = *on;      

On ajoute comme ca

SYSTEM/ADDEXITPGM EXITPNT(QIBM_QSU_ALW_EDIT)
FORMAT(EXTP0100)
PGMNBR(1)
PGM(GDATA/OPENSRCE)
REPLACE(*NO)


Ca ne fait pas tout, que faire si on est 2 sur le même source ? peut être faut il avoir un source de référence pour éviter le versionnage

Remarque :

Pour diminuer le nombre d’appels du programme d’exit , vous pouvez limiter le déclenchement aux fichiers qui sont audités.

Vous devez indiquer le paramètre PGMDTA(*JOB *CALC ‘*OBJAUD’) sur les commandes ADDEXITPGM ou CHGEXITPGM.

Exemple :

ADDEXITPGM EXITPNT(QIBM_QDB_OPEN)

PGMDTA(*JOB *CALC ‘*OBJAUD’)

Vous devez ensuite indiquer les fichiers à auditer :

Exemple :

CHGOBJAUD OBJ(GDATA/QRPGLESRC)
OBJTYPE(FILE) OBJAUD(CHANGE)

A partir de ce moment la, seuls les fichiers audités déclencheront l’appel du programme d’exit QIBM_QDB_OPEN

C’est le nombre de tentatives de connexions pour un profil


Vous pouvez désormais depuis la version 7.5 l’indiquer au niveau du profil et non plus de manière global par la valeurs système QMAXSIGN pas de *NOMAX 25 max

Pour connaitre le nombre de tentatives par profil sur votre ibmi

SELECT AUTHORIZATION_NAME, (CASE MAXIMUM_SIGN_ON_ATTEMPTS
WHEN ‘*SYSVAL’ THEN (select CURRENT_CHARACTER_VALUE
from QSYS2.SYSTEM_VALUE_INFO
where SYSTEM_VALUE_NAME = ‘QMAXSIGN’)
ELSE MAXIMUM_SIGN_ON_ATTEMPTS
END) AS MAXIMUM_SIGN_ON_ATTEMPTS
FROM qsys2.user_info

.

Conseil

Continuez à gérer le plus grand nombre par QMAXSIGN et les exceptions au niveau des profils spécifiques

Quand vous lancerez PRUV avant votre passage en V7R5 vous aurez ce message
qui vous indique que le logiciel 5733OPS n’est plus installable, c’était la première mouture de l’open source sur l’IBMi

SELECT PRODUCT_OPTION, TEXT_DESCRIPTION
FROM QSYS2.SOFTWARE_PRODUCT_INFO
WHERE PRODUCT_ID = ‘5733OPS’

Parmi ces produits vous avez par exemple Nodejs, Nginx, ou Git (Vous devriez déjà utiliser ceux ce de Yum)

il est possible que vous ayez encore des applications qui les utilisent

Pour les trouver, ils utilisent des exécutables différents

Pour 5733OPS

/QOpenSys/QIBM/ProdData/OPS/tools/bin/

Pour RPM YUM

/QOpenSys/usr/bin/

Ou les chercher ?


-dans les scripts sh
-dans les programmes cl utilisant du sh
-dans les paths
-dans les variables d’environnement

Astuce

Pour contrôler après l’installation de votre V7R5
SELECT *
FROM QSYS2.SOFTWARE_PRODUCT_INFO
WHERE LOAD_ERROR = ‘YES’

, , , Gérer les services TCP/IP à Démarrer

Une petite vue synthétique qu’on aime bien dans Navigator for i , qui vous permet en une vue de gérer les services TCP/IP à démarrage automatique

on accède à la vue par là :

Vous avez alors la liste des services avec un tableau qui indique ceux qui sont à démarrage automatique

Vous pouvez choisir les services que vous voulez voir démarrer

Remarque

Si un service ne sert pas arrêtez le !

attention particulièrement au REXEC par exemple

Attention, ça n’arrête pas les services, ils ne seront juste plus démarrés

, , Utiliser un USER SPACE en SQL

Depuis la TR6 de la V7R4, vous pouvez manipuler entièrement les objets de type *USRSPC
Rappel depuis la TR4 vous pouviez les lire

voici la liste des commandes à utiliser avec un exemple

Création, procédure, CREATE_USER_SPACE

CALL QSYS2.CREATE_USER_SPACE(USER_SPACE => ‘MONUSRSPC’,
USER_SPACE_LIBRARY => ‘GDATA’,
SIZE => 100,
PUBLIC_AUTHORITY => ‘*CHANGE’);


Ecriture, procédure, CHANGE_USER_SPACE ou CHANGE_USER_SPACE_BINARY

CALL QSYS2.CHANGE_USER_SPACE(USER_SPACE => ‘MONUSRSPC’,
USER_SPACE_LIBRARY => ‘GDATA’,
DATA => ‘Tester c »est douter , corriger c »est adbiquer’,
START_POSITION => 1);

Lecture, fonction table, USER_SPACE

SELECT Substr(DATA , 1 , 100) FROM TABLE(QSYS2.USER_SPACE(
USER_SPACE => ‘MONUSRSPC’,
USER_SPACE_LIBRARY => ‘GDATA’));

il existe d’autres services SQL , pour manipuler les USER SPACE

QSYS2.USER_SPACE_INFO pour avoir les informations du user space

SELECT * FROM TABLE(QSYS2.USER_SPACE_INFO(
USER_SPACE => ‘USRSPC1’,
USER_SPACE_LIBRARY => ‘GDATA’));

mais aussi pour modifier


QSYS2.CHANGE_USER_SPACE_ATTRIBUTES()

vous pouvez facilement intégrer ces requêtes dans du RPGLE par exemple

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

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

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/fr/i/7.5?topic=supervisor-query-example-exit-programs


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.