Si vous n’administré pas au quotidien votre base de données, mais que vous devez intervenir ponctuellement, Vous avez un lien qui référence les principales opérations à faire et qui peut vous aider
https://www.gaia.fr/wp-content/uploads/2017/02/team3.png600600Pierre-Louis BERTHOIN/wp-content/uploads/2017/05/logogaia.pngPierre-Louis BERTHOIN2023-04-10 09:05:432023-04-10 09:05:44Database Information Finder
Une fois le service configuré et l’extension installée, il nous faut régler quelques options importantes.
Nous allons retrouver des options à deux endroits :
Au niveau de la connexion
Au niveau des options de l’extension :
Déboguer avec VSCode
Il y a plusieurs possibilités dans l’éditeur, nous en choisissons une.
Ouvrez le source du programme à déboguer (on parlera ILE plus tard) :
L’outil vous demande votre mot de passe sur l’IBM i pour valider votre profil, et prompte ensuite la commande d’appel du programme :
Vous basculez alors dans l’affichage du déboguer :
Voyons les outils :
affichage des variables
Affiche les variables locales (quand vous êtes dans une procédure, vous ne voyez que les variables locales de la procédures, pas les variables globales du module).
Vous pouvez copier les valeurs, les modifier, ajouter un guet
Guet (watch)
Affiche, et permet la saisie, de guets de variables.
Pile d’appel
Permet de voir la procédure en cours d’exécution :
L’ordre d’affiche est : procédure / module / programme (de service)
Points d’arrêt
Liste les points d’arrêt, permet la création de nouveaux points et la suppression :
Contrôle de l’avancement
Permet d’avancer dans le débogage :
Dans l’ordre :
Avancer jusqu’au prochain point d’arrêt (équivalent F12 dans STRDBG)
Avancer et entrer en débogage dans la procédure ou programme appelé (équivalent F22 dans STRDBG)
Continuer jusqu’à ressortir de la procédure en cours
restart : non supporté pour l’IBM i
Arrêt du débogage (équivalent F3 dans STRDBG)
Editeur
Identification visuelle de la ligne en cours de débogage (non encore exécutée) :
Point d’arrêt
Pour ajouter un point d’arrêt :
Soit clique gauche dans la marge
Le débogueur s’arrête sur le point d’arrêt au prochain passage.
Les variables modifiées par la dernière instruction sont mises en évidence.
Point d’arrêt conditionné
Commencer par définir le point d’arrêt, puis clique droit -> Editer sur le point :
Puis indiquer votre condition avec la même syntaxe qu’avec STRDBG :
On ne s’arrêtera que lorsque la condition sera vraie !
Par rapport à RDi, le debug de VSCode ne permet pas, pour le moment, les points d’entrée de service ! Il faut donc que VSCode déclenche lui même l’exécution du programme à déboguer ! Gageons la situation évoluera très vite …
Une fois que vous êtes habitués au débogage, regardez les options de couverture de code …
Vous savez peut-être déjà comment créer un point d’arrêt conditionné en Débogage RPG 5250 (commande STRDBG).
Le mode Débogage RDi offre la même possibilité.
Cette fonctionnalité est particulièrement intéressante pour réaliser un Débogage ciblé dans un programme batch qui traite un gros volume de données.
Nous allons le vérifier avec l’exemple ci-dessous :
Considérons une table CLIENTS contenant les colonnes et lignes suivantes :
Le programme PROGTEST lit la tables CLIENTS et exécute la procédure traitement_CLIENTS pour chacun des clients de la table :
Nous allons utiliser le Débogage pour créer un point d’arrêt conditionné sur la ligne d’exécution de la procédure traitement_CLIENTS, afin de pouvoir déboguer ce traitement uniquement pour le client dont le code est 69002.
Point d’arrêt conditionné en Débogage 5250
On crée un point d’arrêt conditionné par une commande BREAK n°ligne WHEN condition
La condition peut utiliser toutes les variables connues du programme, ici le code client = variable CODE
On exécute le programme :
Point d’arrêt juste avant le traitement du client souhaité :
Si on demande la reprise par F12, le programme se poursuit et se termine sans autre point d’arrêt
Point d’arrêt conditionné en Débogage RDi
On crée notre point d’entrée de service pour le programme PROGTEST
On ouvre la perspective Débogage sous RDi puis on exécute le programme en 5250 :
On crée tout d’abord notre point d’arrêt :
Clic droit sur le point d’arrêt + Editer le point d’arrêt :
La condition d’arrêt doit être indiquée sur la ligne « Expression » :
On reprend ensuite l’exécution du programme :
Le programme s’arrête sur notre point d’arrêt pour le client 69002 :
F8=Reprendre –> le programme s’exécute jusqu’à la fin sans nouveau point d’arrêt
Il existe un comcept dans SQL sur les tables qui s’appelle les zones cachées. Je vais essayer de vous expliquer ce que c’est.
Exemple :
CREATE TABLE SALAR ( NUMERO CHAR(6) CCSID 1147 NOT NULL DEFAULT » , NOM CHAR(20) CCSID 1147 NOT NULL DEFAULT » , PRENOM CHAR(30) CCSID 1147 NOT NULL DEFAULT » , SALAIRE DECIMAL(5, 0) NOT NULL DEFAULT 0 IMPLICITLY HIDDEN )
Pour faire simple ces des zones qui n’apparaîtront pas si vous faites un select *
Il y plusieurs buts à cette démarche , caché sommairement des informations ou simplifier des requêtes en cachant des informations utiles et enfin les zones complétables automatiquement les bien connues date, heure et utilisateur de modification. Maintenant que vous savez ce que c’est je vais vous expliquer l’impact sur vos développements existants. D’abord bien sûr si vous avez des select * dans vos développements ça produira une erreur si vous respectez les règles de développement vous ne devriez pas en avoir. Ensuite sur les insert , par défaut il ne connait que les zones non cachées vous devrez indiquer explicitement les zones cachées que vous voulez alimenter.
Conclusion Ça peut être intéressant dans certains cas pour éviter une vue qui aurait juste pour fonction de limiter les zones. Attention toutefois, si voulez utiliser cette possibilité toutes les zones sont visibles dans les invites Sql …
Et enfin une zone ajoutée même en hidden change le niveau de format puisqu’il est calculé sur l’ensemble des zones.
https://www.gaia.fr/wp-content/uploads/2017/02/team3.png600600Pierre-Louis BERTHOIN/wp-content/uploads/2017/05/logogaia.pngPierre-Louis BERTHOIN2023-03-15 10:00:392023-03-21 07:01:33Les zones HIDDEN en SQL
Les tables de conversion sont des objets de type *TBL
Vous en trouvez un grand nombre dans QSYS ou QUSRSYS les 2 plus connues sont
QEBCDIC *TBL QSYS ASCII TO EBCDIC TRANSLATE TO ASCII QASCII *TBL QSYS EBCDIC TO ASCII TRANSLATE TO EBCDIC
elles servent à convertir une donnée, elle sont utilisées dans certaines commandes FTP ou QUERY Etc …
Vous pouvez également les utiliser vous dans vos développements (bien qu’aujourd’hui SQL semble une meilleur alternative)
Imaginons que vous voulez crypter quelque chose par exemple dans une field proc et que pour vous l’utilisation des API Qc3EncryptData et Qc3DecryptData soit un peu compliqué.
Vous pouvez utiliser cette solution c’est pas le top mais la multiplication des moyens de cryptage ralenti les hackers …
Vous devrez donc créer votre table de conversion dans un fichier source le plus souvent QTBLSRC
Vous devez alors compiler votre table par la commande CRTTBL …
j’ai choisi pour mon exercice de faire une table alternative, la première fois elle crypte la deuxième elle decrypte
il existe une API système qui s’appelle QCDXLATE qui a un format très simple
On se demande souvent comment gérer les paramètres de compile sur les PRTF et les DSPF, il existe plusieurs solutions comme créer des CL de compile par exemple, ou utiliser des ALM qui intègrent cette possibilité. Mais comment faire pour que ca marche tout le temps sans avoir à modifier les commandes de compile
Voici une solution qui a été mise au point pour nos clients du centre de service.
On va utiliser le programme d’exit QIBM_QCA_CHG_COMMAND qui, à chaque fois qu’il verra un CRTPRTF l’interceptera.
Pour éviter que cela ne boucle on devra dupliquer la commande CRTPRTF dans une autre bibliothèque et renvoyer sur celle de QSYS quand on aura fait le paramétrage complémentaire.
Cette bibliothèque devra donc être devant QSYS dans la liste des bibliothèques, imaginons que cette bibliothèque s’appelle GDDS.
CHGSYSLIBL LIB(GDDS)
soit DSPLIBL
dans le source de votre PRTF vous allez indiquer des lignes commençant par A*<COMP> et terminées par </COMP>
+ votre mot clé exempleSAVE(*YES) Vous pouvez indiquer plusieurs paramètres sur une seule ligne.
Nous avons 2 programmes que vous pouvez retrouver ici, il vous suffit des les compiler et de les ajouter à la bibliothèque GDDS que vous avez placée en tête de liste
Vous avez donc dans votre bibliothèque 2 programmes et une duplication de la commande CRTPRTF et (du CRTDSPF si vous l’ajoutez)
RTVMBRSRC qui va retrouver à partir de la commande le membre source à compiler GDDS qui prendra la commande et qui lui ajoutera les informations lues dans le fichier source c’est ce programme qu’on devra ajouter au programme d’exit comme ceci : ADDEXITPGM EXITPNT(QIBM_QCA_CHG_COMMAND) FORMAT(CHGC0100) PGMNBR(92) PGM(GDDS/GDDS) TEXT(‘Paramétrage GDDS’) PGMDTA(*JOB 20 ‘CRTPRTF GDDS ‘)
Attention au paramètre PGMDTA, la commande fois faire 10 de long pour que le système la trouve
Vous avez un programme CLLE INITGDDS qui peut vous aider dans le répertoire CLP
==>WRKREGINF QIBM_QCA_CHG_COMMAND puis option 8
Avec cette commande, on prendra en compte désormais les CRTPRTF. A partir de ce moment là, quand vous passerez la commande CRTPRTF, vos paramètres indiqués dans le sources seront ajoutés à la commande.
Par exemple en demandant l’invite sur la commande : CRTPRTF FILE(GDATA/PRTF198) SRCFILE(GDATA/QDDSSRC) SRCMBR(*FILE) Vous aurez vos paramètres
Remarque : Vous pouvez indiquer un programme d’exit pour les DSPF (CRTDSPF), et même si vous avez encore quelque PF (CRTPF), les LF (CRTLF) Bien sûr, tous les mots clés que vous indiquez doivent syntaxiquement être justes et correspondre au type de fichier que vous créez. Cette solution marche en interactif, en batch, par RDI et par Vs Code, dans vos CL de compile etc …
https://www.gaia.fr/wp-content/uploads/2017/02/team3.png600600Pierre-Louis BERTHOIN/wp-content/uploads/2017/05/logogaia.pngPierre-Louis BERTHOIN2023-03-07 05:34:002023-03-07 14:28:16Comment gérer les options de compile des PRTF
Quand on fait des développements, il est parfois nécessaire de verrouiller un programme afin d’empêcher son utilisation par d’autres utilisateurs pendant qu’il est exécuté.
Cependant, il n’est pas possible de verrouiller un programme.
Lorsque on saisit :
Le programme &MONRPG peut être exécuté par un autre utilisateur. Cette commande va verrouiller la description d’objet du programme, mais pas son utilisation.
Alors, comment peut-on gérer le verrouillage d’un programme ?
Une solution possible est d’utiliser une data area qui sera allouée au début du programme avec la commande ALCOBJ. Tant que cette data area sera verrouillée par le travail, aucun autre travail ne pourra se l’allouer.
ATTENTION ! Il est possible de verrouiller à plusieurs reprises le même objet du même travail.
Cette data area restera verrouillée jusqu’à la fin du travail ou jusqu’à ce que on désalloue l’objet avec la commande DLCOBJ (l’objet doit être désalloué autant de fois qu’il a été alloué).
Si l’on ne fait pas DLCOBJ avant ALCOBJ, il peut arriver que :
1. On appelle un programme qu’on a verrouillé par une DTAARA.
2. Le programme plante.
3. L’utilisateur revient dans ce même programme.
4. Il verrouille une fois supplémentaire.
5. Quand il a fini sans problème, il va rester un verrouillage.
Il est donc important de faire DLCOBJ avant un ALCOBJ. Il désalloue ce témoin de verrouillage après usage pour laisser la place libre à un travail suivant.
Et finalement, si l’on veut trouver le travail qui alloue, on peut utiliser la vue qsys2.object_lock_info :.
Egalement appelée clés étrangères, c’est une approche data centrique pour gérer les dépendances des données entre les tables de votre base de données.
Prenons un exemple :
Une commande ne peut pas avoir un client qui n’existe pas et à l’inverse, vous ne pouvez pas supprimer un client qui a encore des commandes
Jusqu’à maintenant, on avait tendance à laisser gérer cette dépendance à l’application, ce qui immanquablement créait des orphelins, qu’on devait corriger par des programmes de contrôle
Il existe donc une alternative c’est de demander à SQL de gérer cette dépendance, c’est l’approche data centrique, voyons comment
Dans la bibliothèque PLB nous allons créer 2 tables
tclients pour les clients
CREATE TABLE PLB.TCLIENTS ( NUMERO CHAR(6) CCSID 1147 NOT NULL DEFAULT » , NOM CHAR(30) CCSID 1147 NOT NULL DEFAULT » )
ALTER TABLE PLB.TCLIENTS ADD CONSTRAINT PLB.Q_PLB_TCLIENTS_NUMERO_00001 PRIMARY KEY( NUMERO )
Cette table doit impérativement avoir une clé primaire sur la clé que vous voulez contrôler ici NUMERO
tcommande pour les commandes
CREATE TABLE PLB.TCOMMANDE ( NUMERO CHAR(6) CCSID 1147 NOT NULL DEFAULT » , NUMEROCDE CHAR(6) CCSID 1147 NOT NULL DEFAULT » , DESCRCDE CHAR(30) CCSID 1147 NOT NULL DEFAULT » )
ALTER TABLE PLB.TCOMMANDE ADD CONSTRAINT PLB.Q_PLB_TCOMMANDE_NUMEROCDE_00001 UNIQUE( NUMEROCDE ) ;
On ajoute une clé sur le numéro de commande qui ne sert pas pour la contrainte, mais qui logiquement serait présente pour identifier votre commande
Mise en Œuvre
Pour ajouter votre contrainte vous avez 2 solutions
ALTER TABLE PLB.TCOMMANDE ADD CONSTRAINT PLB.Q_PLB_TCOMMANDE_NUMERO_00001 FOREIGN KEY( NUMERO ) REFERENCES PLB.TCLIENTS ( NUMERO ) ON DELETE RESTRICT ON UPDATE RESTRICT ;
Vous fixez une action sur le fichier parent, en cas de non respect de la règle posée, le plus souvent on met RESTRICT qui interdira l’opération. Vous pouvez regarder les autres actions pour voir , attention à *CASCADE qui peut être très brutal …
En ajoutant votre contrainte, vous pouvez avoir ce message qui indique que des valeurs ne respectent pas la régle de contrôle énoncée
Message . . . . : Les valeurs de clé de la contrainte référentielle sont incorrectes.
Cause . . . . . : La contrainte référentielle Q_PLB_TCOMMANDE_NUMERO_00001 du fichier dépendant TCOMMANDE, bibliothèque PLB, est en instance de vérification. Le fichier parent TCLIENTS, bibliothèque PLB, possède une règle de suppression de *RESTRICT et une règle de mise à jour de *RESTRICT. La contrainte est en instance de vérification car l’enregistrement 2 du fichier dépendant comporte une valeur de clé étrangère qui ne correspond pas à celle du fichier parent pour l’enregistrement 0. Si le numéro d’enregistrement du fichier parent ou du fichier dépendant est 0, l’enregistrement ne peut pas être identifié ou ne satisfait pas à l’état vérification en instance.
A ce moment la contrainte est active mais vous avez des enregistrements non conformes vous pouvez les voir par WRKPFCST
l’option 6 permet de voir les enregistrements en attente de validation et en erreur
Testons, si vous essayez de créer une commande avec un client qui n’existe pas vous aurez un message de ce type par DFU ou dans un programme RPGLE
Message . . . . : Violation de contrainte référentielle sur le membre TCOMMANDE.
Cause . . . . . : L’opération en cours sur le membre TCOMMANDE, fichier TCOMMANDE, bibliothèque PLB a échoué. La contrainte Q_PLB_TCOMMANDE_NUMERO_00001 empêche l’insertion ou la mise à jour du numéro d’enregistrement 0 dans le membre TCOMMANDE du fichier dépendant TCOMMANDE dans la bibliothèque PLB : aucune valeur de clé correspondante n’a été trouvée dans le membre TCLIENTS du fichier parent TCLIENTS de la bibliothèque PLB. Si le numéro d’enregistrement est zéro, l’erreur s’est produite lors d’une opération d’insertion. La règle de contrainte est 2. Les règles de contrainte sont les suivantes : 1 — *RESTRICT
dans vos programmes RPG vous pourrez par exemple utiliser les fonctions %error()
Maintenant essayons de voir ce qui ce passe dans un programme SQLRPGLE, ce qui est la norme de développement à ce jour
**FREE
// création d'une commande avec un client qui n'existe pas
exec sql
INSERT INTO PLB/TCOMMANDE VALUES('000004', '000007',
'Lunettes bleaues') ;
dsply ('Insert : ' + %char(sqlcode)) ;
// modification d'une commande avec un client qui n'existe pas
exec sql
UPDATE PLB/TCOMMANDE SET NUMERO = '000007' ;
dsply ('Update : ' + %char(sqlcode)) ;
// supression d'un client qui a des commandes
exec sql
DELETE FROM PLB/TCLIENTS WHERE NUMERO = '000001' ;
dsply ('delete : ' + %char(sqlcode)) ;
*inlr = *on ;
Vous pouvez faire un DSPFD exemple : DSPFD FILE(PLB/TCOMMANDE) TYPE(*CST)
Par les vues SQL exemple
SELECT * FROM qsys2.SYSCST WHERE TDBNAME = ‘PLB’ and TBNAME = ‘TCOMMANDE’ and CONSTRAINT_TYPE = ‘FOREIGN KEY’ ;
Vous pouvez les administrer par la commande WRKPFCST exemple : QSYS/WRKPFCST FILE(PLB/TCOMMANDE) TYPE(*REFCST)
Avec l’option 6 vous pourrez par exemple voir les enregistrements en instance de vérification, c’est la commande DSPCPCST, pas de sortie fichier !
Conseil :
C’est une très bonne solution sur vos nouvelles bases de données, mais attention l’ajouter sur des bases de données existantes peut être risqué en effet certain traitements pouvant essayer de bypasser ce contrôle, ou avoir des erreurs présentes sur votre base …
Astuces
Vous pouvez utiliser une contrainte temporaire pour vérifier les orphelins de votre base :
Ajout de la contrainte
DSPCPCST pour voir les erreurs
Retrait de la contrainte
Cette opération doit se faire hors activité utilisateur !
SYSCST La vue SYSCST contient une ligne pour chaque contrainte du schéma SQL. SYSREFCST La vue SYSREFCST contient une ligne pour chaque clé étrangère du schéma SQL. SYSKEYCST La vue SYSKEYCST contient une ou plusieurs lignes pour chaque UNIQUE KEY, PRIMARY KEY ou FOREIGN KEY dans le schéma SQL. Il existe une ligne pour chaque colonne dans chaque contrainte de clé unique ou primaire et les colonnes de référence d’une contrainte référentielle. SYSCHKCST La vue SYSCHKCST contient une ligne pour chaque contrainte de vérification dans le schéma SQL. Le tableau suivant décrit les colonnes de la vue SYSCHKCST. SYSCSTCOL La vue SYSCSTCOL enregistre les colonnes sur lesquelles les contraintes sont définies. Il existe une ligne pour chaque colonne dans une clé primaire unique et une contrainte de vérification et les colonnes de référence d’une contrainte référentielle. SYSCSTDEP La vue SYSCSTDEP enregistre les tables sur lesquelles les contraintes sont définies.
Nous rencontrons régulièrement dans les applications historiques, des dates stockées en base de données sous des types autres que date. Dans du numérique, 6 dont 0, 8 dont 0, dans de l’alpha, sur 6, 8 ou 10, dans des colonnes distinctes, SS, AA, MM, JJ….
Dans la plupart des applicatifs, il existe des programmes, ou des fonctions ile, permettant de convertir ces champs en « vrai » format date, en gérant les cas limite. Si date = 0, ou si date = 99999999, 29 février…
Dans des programmes avec des accès natifs à la base de données, ces programmes / fonctions remplissent leur rôle parfaitement.
Par contre dès qu’on choisit d’accèder à la base de données par SQL, nous constatons que ces programmes sont peu à peu délaissés pour des manipulations de date directement dans les réquêtes SQL, avec des requêtes alourdit à base de case et de concat. Pour harmoniser les règles de conversion, et allèger visuellement vos requêtes, vous pouvez créer votre propre fonction SQL, qui rendra les mêmes services que les programmes existants.
Prenons l’exemple, rencontré chez un client, d’un ERP qui stocke les dates sous un type numérique de 7 dont 0. La première position contient 0 ou 1 pour le siècle. 0 =19 et 1 = 20.
Dans cette base :
950118 = 18/01/1995
1230118 = 18/01/2023
on peut trouver les valeurs 0 et 9999999 qui ne sont pas des dates, et qu’il faudra gérer lors de la conversion
on peut trouver des fausses dates : 29022023, 31092022…
Nous allons créer une fonction SQL qui permettra de gérer la conversion de ces colonnes en « vraie » date.
Pour la gestion des cas limites, j’ai choisi les règles suivantes, à chacun d’adapter en fonction de ses besoins :
9999999 –> 31/12/9999
0 soit null si 0 passé en second paramètre, soit 01/01/Année passée en second paramètre
les dates inexistantes –> null
Notre jeu d’essai est composé d’une table avec 3 colonnes numérique de 7 dont 0 avec 4 enregistrements :
Pour créer nos propres fonctions SQL, on peut le faire directement en mode script via un requêteur SQL, ou utiliser une fonction d’ACS qui permet une préconfiguration en mode graphique. Je vais détailler cette seconde méthode.
Dans le bloc « Base de données » d’ACS, sélectionner l’option Schémas
Déplier l’arborescence, de votre base de données et Schémas.
Il va falloir se positionner sur le schéma (la bibliothèque) qui contiendra la fonction SQL. Je vous conseille d’utiliser la bibliothèque contenant vos données métier, pour en faciliter l’utilisation dans vos applications. Si les données sont en ligne, la fonction le sera aussi !
Déplier l’arboresence au niveau du schéma souhaité et cliquer sur l’item « Fonctions ».
La liste des fonctions déjà existantes dans ce schéma apparait dans la partie droite….
Par clic droit sur l’item « Fontions », choisir dans le menu, « Nouveau », puis « SQL »
Dans la fenêtre de paramétrage, on va se déplacer d’onglet en onglet.
Saisir le nom pour votre fonction.
Onglet « Paramètres » par le bouton sur la droite « Ajout… », on va déclarer les paramètres en entrée de la fonction, en premier un numérique de 7 dont 0 et en second un numérique de 4 dont 0 pour passer une année par défaut en cas de 0.
Pour l’année par défaut, nous ajoutons une valeur par défaut, 0. Nous verrons l’intérêt de cette valeur par la suite.
Onglet « Retours », nous déclarons la valeur de retour, soit une date au format date.
Onglet Options : cet onglet permet de fixer le contexte d’éxecution de la fonction, et donc le bon fonctionnement de la fonction ainsi que son optimisation. Par rapport aux valeurs par défaut, j’ai modifié 2 paramètres :
– Accès aux données. Ma fonction n’accèdera à aucune table, j’ai donc choisi l’option « Contient SQL ». Si ma fonction devait accèder à des tables en lecture uniquement, il faudrait laisser l’option par défaut « Lit des données SQL », enfin si la fonction devait mettre à jour des tables, l’option « Modifie des données SQL ».
– Même valeur renvoyée à partir d’appels successifs pour des paramètres identiques. En cochant cette case, j’autorise le moteur SQL à enregistrer le résultat de la fonction avec les paramètres d’appel dans le cache SQL et de réutiliser ce résultat sans éxécuter la fonction en cas d’appel avec les mêmes paramètres. 1230118 renverra toujours 18/01/2023. Et Date = 0, an par défaut = 0 renverra toujours null…
Ces paramètres sont à fixer selon l’usage mais aussi le code utilisé dans la fonction.
Onglet « Corps de routine », il ne reste plus qu’à coder la fonction en SQL procédural. Pour rappel, on encadre le code par « BEGIN (sans ;) / end (sans ; ) », dans l’interface graphique… Dans un script SQL, il faut bien ajouter un « ; » après le end. Les conditoinnements ne prennent de « ; » que sur le end Les instructions autres se terminent par un « ; » On peut utiliser des variables de travail, il faut les déclarer par …. Declare ! La valeur retour est renvoyées par l’instruction return.
Vous pouvez maintenant utiliser votre fonction, que ce soit par un scripteur SQL, dans vos SQLRPGLE, dans des scripts SQL lancé par runsqlstm…
Vous constaterez que je n’ai passé que le 1er paramètre à ma fonction. Le second ayant une valeur par défaut, il devient facultatif. Ce qui veut dire, que si vous avez besoin de rajouter un paramètre à une fonction SQL déjà existante, ajouter une valeur par défaut permet de ne pas avoir à reprendre l’existant. Seuls les cas nécéssitant ce nouveau paramètre seront à traiter.
Si nous lançons la fonction sur la colonne DATEERP3 qui contient une valeur qui n’est pas une date, 1230229, la requête plante :
Les résultats s’arrêtent dès le crash et ne renvoit que les deux premiers enregistrements dont la résolution de la fonction était ok :
Il faut ajouter une gestion d’erreurs à notre fonction.
Et c’est une règle d’or sur les fonctions personnalisées. Vous n’avez le droit à aucun plantage de la fonction, au risque de traiter dans vos programmes des résultats tronqués si la gestion des sqlcode / sqlstate n’est pas faite.
En début de script, je rajoute le monitoring, sur le SQLSTATE renvoyé par l’erreur et je choisit de renvoyer la valeur null :
N’ayant pas beaucoup d’instructions dans ma fonction, je me contente de cette gestion d’erreur. Dans des cas plus complexe, ne pas hésiter à monitorer avec un SQLEXCEPTION
Maintenant la fonction renvoie null si la date n’existe pas et nous avons les résultats pour nos 4 enregistrements.
Si nous lançons la fonction sur la colonne DATEERP2 qui contient des dates valides et la valeur 9999999, nous constatons
que deux dates ne sont pas traduites :
Vu que je n’ai monitoré que le sqlstate 220007, nous savons que c’est pour date invalide que la conversion n’a pas eu lieu. Le problème vient du format de date dans ma fonction SQL, par défaut *YMD
Ce format de date est limité dans le temps au 31/12/2039…
Il faut passer en format *iso pour convertir des dates au-delà de 2039, et donc pour cela modifier le set option par défaut.
Maintenant, tout fonctionne comme voulu, ma fonction est opérationnelle :
Vous pouvez continuer à utiliser les programmes existants pour ces conversion, mais dans ce cas il faut interdire à vos développeurs la conversion dans les requêtes SQL.
L’avantage de passer par une fonction SQL, c’est que cette fonction peut aussi être utilisée par des applicatifs distants qui viennent requêter sur la base de données. Appli web, bien entendu, mais aussi les ETL, comme Talend, et de garder la main sur les règles de conversion, plutôt que de les déporter sur chaque outil.
https://www.gaia.fr/wp-content/uploads/2025/02/DT-1-e1739799848306.png205175Damien Trijasson/wp-content/uploads/2017/05/logogaia.pngDamien Trijasson2023-01-30 17:49:172025-02-17 14:47:17Conversion en format date par fonction SQL