, , Comment suivre son plan de production quotidien ?

Supposons que vous utilisiez le job scheduler de l’IBMi, (WRKJOBSCDE), si vous utilisez AJS seul le fichier de départ change mais la démarche reste la même.

Notre méthode ne marche que pour le jour courant.
On va utiliser la date de prochaine soumission égale à la date du jour dans notre fichier SCHEDULED_JOB qui contient les jobs planifiés .

Vous devez planifier un job tous les matins à 0h et 2 minutes dans la file d’attente QCTL pour être sûr de le faire passer

Ce job aura une requête de ce type qui créera une table plandujour

create table plandujour as (
Select SCHEDULED_JOB_NAME, SCHEDULED_TIME,
ifnull(DESCRIPTION,  »  ») as description
from QSYS2.SCHEDULED_JOB_INFO
where NEXT_SUBMISSION_DATE = current date and
substr(SCHEDULED_JOB_NAME, 1, 1) <>  »Q »
and status <>  »HELD »
order by SCHEDULED_TIME ) with data +

Vous avez ainsi tous les jobs prévus pour la journée par heure de planification.

Maintenant nous allons voir comment suivre le déroulement des ces travaux

Pour suivre vos travaux on va utiliser la fonction table suivante HISTORY_LOG_INFO

exemple pour avoir les jobs du jour

SELECT * FROM TABLE(QSYS2.HISTORY_LOG_INFO(CURRENT DATE)) X

Chaque job qui tourne sur le système va générer au moins 2 messages

un CPF1124 Travail …/…/… démarré le
un CPF1164 Travail …/…/… arrêté le

donc
si votre travail n’a pas tourné vous n’avez aucun message
si votre travail tourne vous avez un CPF1124
si votre travail est terminé vous avez un CPF1164

Vous pouvez déjà suivre l’avancement grâce à la zone MESSAGE_TIMESTAMP et avoir une durée entre les 2 messages

Remarque :

pour savoir si votre travail c’est terminé normalement c’est un peu plus compliqué, vous devrez analyser le code fin par exemple dans la zone MESSAGE_TEXT.

code fin 0 indiquant une fin normale du traitement

Un exemple de requête (à améliorer)

pour les codes fin , pour les jobs qui débordent de la journée etc…

WITH logdujour (mgr_id, mgr_name, mgr_dept) AS(
SELECT * FROM TABLE(QSYS2.HISTORY_LOG_INFO(CURRENT DATE)) X)
select
a.SCHEDULED_JOB_NAME as nom_travail,
a.SCHEDULED_TIME as
HEURE_prev ,
ifnull(b.MESSAGE_TIMESTAMP,  »1911-11-11-00.00.00.00000 ») as Heure_debut ,
ifnull(c.MESSAGE_TIMESTAMP,  »1911-11-11-00.00.00.00000 ») as heure_fin,
ifnull(c.SEVERITY, »99 ») as code_sev ,
ifnull(b.FROM_JOB,  »  ») as name_JOB
from plandujour a
Left outer join logdujour b
on B.MESSAGE_ID = »CPF1124 » and B.FROM_JOB like( »% » concat
A.SCHEDULED_JOB_NAME concat  »% »)
Left outer join logdujour c
on C.MESSAGE_ID = »CPF1164 » and C.FROM_JOB like( »% » concat
A.SCHEDULED_JOB_NAME concat  »% »)

Vous pouvez planifier un job chaque soir qui vous envoie un récapitulatif de la journée, ou que les jobs en erreur par exemple.

Vous pouvez historiser ces données si vous avez besoin de consolider un suivi, etc …

Exemple d’un outil packagé utilisé dans notre centre de service pour suivre le planning quotidien:

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

, , SQL nom court / nom long

Rappel :

Pour les noms des objets collection, table, index, view, etc … le système maintient en double un nom SQL et un nom IBM i
Exemple :
SQL / bd_des_articles et IBMi / BD_DE00001
la règle est la suivante pour les noms supérieurs à 10 caractères le système prends les 5 premières positions et incrémente un compteur sur 5 positions, ce qui n’est pas forcément très lisible.

pour éviter ça, il est conseillé d’indiquer les 2 au moment de la création de votre objet SQL

Bien sur vous ne pourrez pas avoir des doublons ni sur le nom long ni sur le nom court

Voici quelques conseils

Création d’une base de données

Par un create schema par exemple

vous indiquez le nom SQL et vous pouvez forcer un nom court par la clause FOR SCHEMA nomcourt

exemple

CREATE SCHEMA BASE_DE_DONNEES_ARTICLES FOR SCHEMA DBARTICLE

Création d’une table

create table

vous indiquez le nom SQL et vous pouvez définir un nom court par la clause SYSTEM NAME nomcourt
il est conseillé pour les mêmes raisons de mettre sur un nom court, un nom long par la clause FOR nomcourt

EXEMPLE

CREATE TABLE DBARTICLE.Fichier_ARTICLES FOR SYSTEM NAME ARTICLES (
NUMERO_ARTICLE FOR COLUMN NUMART DEC ( 6) NOT NULL WITH DEFAULT,
NOMCLI_ARTICLE FOR COLUMN NOMART CHAR ( 30) NOT NULL WITH DEFAULT)

vous pouvez utiliser indifféremment les 2 syntaxes

select
NUMART ,
NOMART
from DBARTICLE.Fichier_ARTICLES
ou

select
NUMERO_ARTICLE ,
NOMART
from DBARTICLE.ARTICLES

pour la plupart des autres objets vous pouvez indiquer la clause FOR SYSTEM NAME nomcourt

Création d’un index

CREATE INDEX nomlong FOR SYSTEM NAME nomcourt
ON bd (long ou court)/ table (nom court ou long)
(nom de zone court ou long)

Exemple

CREATE index DBARTICLE.key_articles_numcli FOR SYSTEM NAME key_numli
on DBARTICLE.ARTICLES
(NUMERO_ARTICLE)

Création d’une vue

CREATE VIEW … FOR SYSTEM NAME nomcourt ()

exemple

CREATE VIEW DBARTICLE.articles_nom_b FOR SYSTEM NAME articleb (
NUMERO_ARTICLE , NOMART )
as
(select
NUMERO_ARTICLE , NOMART
from DBARTICLE.ARTICLES
where NUMART like(‘B%’))

Remarques :

Vous pouvez créer une table en faisant un create table as

exemple

CREATE table DBARTICLE.articles_nom_c FOR SYSTEM NAME articlec as
(select
NUMERO_ARTICLE , NOMART
from DBARTICLE.ARTICLES
where NUMART like(‘B%’))
With data

Ce qui permet de récupérer les attributs des zones de la table

Vous pouvez renommer une zone

exemple

CREATE table DBARTICLE.articles_nom_cbis FOR SYSTEM NAME article1 as
(select
NUMERO_ARTICLE , NOMART as nom_article_bis
from DBARTICLE.ARTICLES
where NUMART like(‘B%’))
With data

Mais c’est une nouvelle zone et le nom court est conservé, bien sur sauf si c’est une zone de travail substr par exemple ….

Si vous souhaitez utiliser vos tables en RPG, vous pouvez préciser un nom de format, ce qui vous evitera un renommage dans le programme RPGLE
c’est en utilisant la clause RCDDFMT
CREATE TABLE nomdb.nomtable ( ) RCDFMT nomfmt

Exemple

CREATE TABLE DBARTICLE.Fichier_ARTICLES FOR SYSTEM NAME ARTICLES (
NUMERO_ARTICLE FOR COLUMN NUMART DEC ( 6) NOT NULL WITH DEFAULT,
NOMCLI_ARTICLE FOR COLUMN NOMART CHAR ( 30) NOT NULL WITH DEFAULT)
RCDFMT ARTICLEF

Pour connaitre les correspondances sur les objets existants, vous pouvez utiliser les vues SQL

pour les tables
SELECT TABLE_NAME, SYSTEM_TABLE_NAME FROM systables
where …

pour les index

SELECT INDEX_NAME, SYSTEM_INDEX_NAME FROM SYSINDEXES
where

pour les vues

SELECT TABLE_NAME, SYSTEM_VIEW_NAME FROM sysviews
where

oui la vue s’appelle TABLE_NAME ?????????? ça sent le copier coller …

on peut renommer des noms systèmes sur des objets SQL

Exemples

RENAME TABLE GDATA.LONG_NOM_TABLE TO SYSTEM NAME LONG_NOM

RENAME index GDATA.LONG_INDEX_ZONE1 TO SYSTEM NAME I_ZONE1

RENAME index GDATA.LONG_VIEW_ALL TO SYSTEM NAME LONG_VIEW

Complément

Particularité pour renommer une table

Nous créerons la table suivante

CREATE TABLE gdata/nom_long_table FOR SYSTEM NAME nom_court (
NUMERO_ARTICLE FOR COLUMN NUMART DEC ( 6) NOT NULL WITH DEFAULT,
NOMCLI_ARTICLE FOR COLUMN NOMART CHAR ( 30) NOT NULL WITH DEFAULT)

rappel
Une table a un nom long et un nom court qui doivent être unique

on essaye de dupliquer la table dans la même bibliothèque

CRTDUPOBJ OBJ(NOM_COURT)
FROMLIB(GDATA)
OBJTYPE(FILE) TOLIB(GDATA) NEWOBJ(NOM_COURT2) DATA(YES)

duplication impossible dans la même bibliothèque, le probléme étant sur le nom long qui est dupliqué

Le message est le suivant
Le nom de remplacement attribué au fichier NOM_COURT2 n’est pas admis.

Pour dupliquer votre table vous devez donc passez par SQL

create table gdata/nom_long_table2 like gdata/nom_long_table

vous obtenez bien une 2éme table qui se nomme nom_long_table2

Mais le nom ibmi est fixé par le système ici NOM_L00001
est si vous voulez le renommer vous pouvez le faire par RNMOBJ

RNMOBJ OBJ(GDATA/NOM_L00001) OBJTYPE(*FILE) NEWOBJ(NOM_COURT2)

Vous avez nom long nom_long_table2
Vous avez nom court nom_court2

Vous devez bien faire les 2 opérations

Si vous voulez juste sauvegarder les données

Préférer un create table as en SQL ou un cpyf crtfile(*YES) en IBMI

, , 5 astuces pour optimiser vos connexions ODBC.

On a souvent du mal a régler ODBC voici quelques points qui peuvent vous aider dans cette tache.
L’apport de la procédure SET_SERVER_SBS_ROUTING qui permet de router des jobs ODBC, par adresses IP ou utilisateurs à considérablement changer la donne.

Rappel sur la procédure SET_SERVER_SBS_ROUTING

Gestion par utilisateur

call qsys2.SET_SERVER_SBS_ROUTING(‘PLB’, ‘QZDASOINIT’ , ‘ODBC’)

pour activer la redirection

call qsys2.SET_SERVER_SBS_ROUTING(‘PLB’, ‘QZDASOINIT’ , NULL);

pour supprimer cette redirection

SELECT * FROM QSYS2.SERVER_SBS_ROUTING

Pour les redirections existantes par nom user

Gestion par adresse IP

Pour activer

CALL QSYS2.SET_SERVER_SBS_ROUTING(AUTHORIZATION_NAME => ‘*ALL’,
SERVER_NAME => ‘QZDASOINIT’,
IP_ADDRESS_START => ‘192.168.1.10’,
IP_ADDRESS_END => ‘192.168.1.30’,
SUBSYSTEM_NAME => ‘ODBC’)

Pour supprimer cette redirection

CALL QSYS2.SET_SERVER_SBS_ROUTING(AUTHORIZATION_NAME => ‘*ALL’,
SERVER_NAME => ‘QZDASOINIT’,
IP_ADDRESS_START => ‘192.168.1.10’,
IP_ADDRESS_END => ‘192.168.1.30’,
SUBSYSTEM_NAME => NULL);

pour voir les redirections existantes par adresses IP

SELECT * FROM QSYS2.SERVER_SBS_CONFIGURATION;

Voici quelques axes qui peuvent vous donner des idées

1) Séparer vos connexions en créant un sous-système spécifique

Ce qui permet une meilleur administration.
Vous pourrez router vos jobs par utilisateurs ou par adresse IP grâce à la procédure SQL SET_SERVER_SBS_ROUTING

CRTSBSD SBSD(VOTRESBS)
POOLS((1 *BASE))
TEXT(‘Sous-système pour job ODBC’)
vous pouvez indiquer le pool de base

un travail à démarrage automatique

ADDPJE SBSD(GODBC) PGM(QSYS/QZDASOINIT) INLJOBS(QZDASOINIT) JOBD(Qgpl/votrejobd) CLS(QSYS/votreclasse) user(votreuser)

et un poste de routage

ADDRTGE SBSD(VOTRESBS)
SEQNBR(9999)
CMPVAL(*ANY)
PGM(VOTREPGM)
CLS(VOTRECLASS)

2) Mettre un pool spécifique sur votre sous système

Ce qui permettra de réinitialiser votre cache entre 2 benchmarks.

POOLS((1 *SHRPOOL7))

3) Mettre une classe spécifique

Ce qui permettra de régler les priorités d’exécution sur la commande RTGE.
la classe par défaut est la QPWFSERVER , dupliquez la et ajustez les paramètres que vous désirez par CHGCLS.
Par exemple, les priorités.

4) Mettre une JOBD spécifique pour fixer le niveau de log

par exemple sur la commande ajout des travaux auto.
la jobd par défaut est la QDFTSVR , dupliquez la et ajustez les paramètres que vous désirez par CHGJOBD.
Par exemple le niveau de log.

5) Mettre un programme initial spécifique

Pour par exemple choisir le fichier QAQQINI pour les réglages SQL.
Le programme par défaut est QCMD , voici un exemple.
Par exemple, changer le fichier QAQQINI
PGM
CHGQRYA QRYOPTLIB(&LIB)
SNDPGMMSG MSGID(CPF9898) MSGF(QCPFMSG) MSGDTA(‘Vous +
utilisez désormais QAQQINI de la +
bibliothèque, ‘ BCAT &LIB) MSGTYPE(STATUS)
ENDPM

Rappel :

Ici on traite pas de la traçabilité, il est important de voir qui peut faire de l’ODBC sur votre système.

Nous avons un logiciel GODBC qui peut vous aider dans cette tache ici : https://www.gaia.fr/produits/

, , Moderniser vos menus IBMi

Vous pouvez désormais accéder aux fichiers des messages par SQL grâce à la vue SQL QSYS2.MESSAGE_FILE_DATA.

Vos menus personnalisés utilisent des commandes qui sont stockés dans des fichiers messages.

Voici une idée pour améliorer vos menus : prendre la commande à exécuter et l’afficher, vous pouvez customizer l’affichage du texte

J’ai publié le code sur github l’adresse suivante : https://github.com/Plberthoin/PLB/tree/master/GTOOLS

Vous devez récupérer, un DDS , un SQLRPGLE et une CMD.

Voila qui peut vous donner des idées pour la gestion de vos fichiers messages

, Télécharger PTF par FTPS

Téléchargement de PTF par FTP

Depuis mi-juillet 2021, ce n’est plus un choix le mode FTP simple en anonymous ne fonctionne plus, vous le voyez quand vous allez sur fix central le mode ftps ou sftp est par défaut .

Quand vous faites votre demande vous recevez désormais 3 mails au lieu de 2
– Le premier, pour vous dire que votre demande a été prise en compte.
– Le deuxième, pour vous indiquer les instructions à passer pour votre téléchargement
– Le Troisième (nouveau) qui contiendra le mot de passe que vous devrez utiliser

Comment faire désormais pour télécharger ces PTFs, on va voir 2 méthodes ?

1) A partir de Filezilla


Le logiciel connait le certificat racine Digicert, donc si vous vous connectez en SSL sur le site delivery01-bld.dhe.ibm.com, il vous propose la première fois de télécharger le certificat.

Et vous pouvez faire ensuite votre téléchargement .

2) A partir de votre partition IBMi

Il va vous falloir installer le certificat racine Digicert et le certificat du site dans DCM qui gère les certificats du coté IBMi.

Il est conseillé pour faire ses installations d’utiliser le logiciel QMGTOOLS.

Nous vous conseillons également de le mettre à jour pour éviter les problèmes.

ADDLIBLE LIB(QMGTOOLS)
GO MENU(MG)

  1. Check IBM for updated QMGTOOLS

Vous pouvez donc maintenant faire vos installations

Le certificat racine est disponible ici

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

Vous devez dezipper vos fichiers et les copier dans l’IFS de votre IBMi par exemple /temp

Vous allez utilisez la première commande suivante
GETSSL pour le certifcicat racine
détail ici
https://www.ibm.com/support/pages/node/683901
et pour installer le certificat vous allez à nouveau utiliser la commande GETSSL avec le paramétrage suivant
QMGTOOLS/GETSSL IP(WWW.ECUREP.IBM.COM)
PORT(443)
AUTOIMP(Y)
STOREPWD(‘votre mot de passe’)

Si vous allez dans DCM vous avez un nouveau certificat installé QMG0001

Vous pouvez désormais vous connecter au site avec la commande suivante

FTP RMTSYS(‘delivery01-bld.dhe.ibm.com’) SECCNN(*SSL)

Attention cependant vous devrez forcer le mode par la commande FTP SENDEPRT

Voila, une fois que vous avez paramétré vous pouvez utiliser télécharger vos PTFs comme avant.

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

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