DB2/400 : triggers en V5R10

BoTTom |    Changer de couleur
 Trigger : Pgm associé à une action base de données (insert, update, delete)
 
           cde OS/400: Ajouter déclencheur fich physique ( ADDPFTRG )
 
 ...........................................................................
 :                                                                         :
 : Fichier physique . . . . . . . . > CLIENTP       Nom                    :
 :   Bibliothèque . . . . . . . . .     *LIBL       Nom, *LIBL, *CURLIB    :
 : Moment de déclenchement  . . . . > *BEFORE       *BEFORE, *AFTER        :
 : Evénement de déclenchement . . . > *UPDATE       *INSERT, *DELETE, *UPD :
 : Programme  . . . . . . . . . . . > TRIGGER1      Nom                    :
 :   Bibliothèque . . . . . . . . .     *LIBL       Nom, *LIBL, *CURLIB    :
 :.........................................................................:
 
  Le trigger, s'il est écrit en L3G (RPG ou COBOL) recoit deux paramètres:
 
              1/ une structure contenant a/ des infos système
                                         b/ les données manipulées
              2/ la longueur de 1/
 
  Il peut enfin, signaler son désaccord, en envoyant un message d'erreur
 


|    Changer de couleur
 le buffer change en V5R10, il faut IMPERATIVEMENT utiliser les décalages
     (offsets) indiqués en 48 et 64 (faire +1 pour avoir la position).
 
   Dépl   Type              Champ 
     0   Char(10)    Nom du fichier physique
    10   Char(10)    Nom de la librairie
    20   Char(10)    Nom du membre
    30   Char(1)     Evénement déclencheur   1=INSERT,2=DELETE,3=UPDATE,4...
    31   Char(1)     Moment du déclenchement 1=AFTER,2=BEFORE
    32   Char(1)     Niveau de verrouillage de la définition de validation
                                             (0=*NONE,1=*CHG,2=*CS,3=*ALL)
    36   Binary(4)   CCSID des données (297 ?)
    40   Binary(4)   N° de rang de l'enregistrement
    48   Binary(4)   Image avant : Déplacement de l'enregistrement
    52   Binary(4)                  Longueur de l'enregistrement
    56   Binary(4)                 Déplacement de la description des champs
    60   Binary(4)                  Longueur de la description des champs
    64   Binary(4)   Image après : Déplacement de l'enregistrement
    68   Binary(4)                  Longueur de l'enregistrement
    72   Binary(4)                 Déplacement de la description des champs
    76   Binary(4)                  Longueur de la description des champs
    ??   Char(*)     Début de la zone variable


|    Changer de couleur
  cette partie variable contient :
    -                              enregistrement version avant.
    -                               indicateurs de nullité (avant), 1/zone
    -                              enregistrement version après.
    -                               indicateurs de nullité (après), 1/zone
 
 soit un fichier article avec le buffer suivant
 
      | codearticle |  libellé                   |  datecrt   |
      |             |                            |            | 
 
 le trigger recoit un paramètre
         4      6 
  infos  9      5      | code |libellé |date | null | code |libellé |date |
 |       | Dep1 | Dep2 |                     |../.. |                     | 
            !     !    ^                            ^
            !-----!----!                            !
                  !                                 !
                  !---------------------------------!
 
 infos représente toutes les informations systèmes dont nous venons de voir
  le détail


|    Changer de couleur
 
 
 dep1 indique le déplacement pour aller à la version avant du buffer
 dep2  "       "    "          "   "           "     après du buffer
 
 Vous devez absolument utiliser ces deux déplacements (dep1 et dep2)
   pour accèder aux data, la position exacte pouvant changer d'une version
   à l'autre.
 
 La position de dep1 et dep2 étant elle même immuable, bien sûr.
 
 
 null contient dans notre cas trois octets contenant '0' ou '1'
 
  le premier octet contient '0' si code article est significatif
                            '1' si code article contient null
 
   etc pour les deux autres champs.
 
  la fonction %NULLIND() du RPG étant inutilisables (réservées au zones
    venant de fichiers, et dans notre cas il n'y a pas de spécif F)
 


|    Changer de couleur
 
 la gestion des triggers est elle même modifiée en V5.10 :
 
 -un trigger peut être suspendu
 
 -on peut associer 300 triggers à un fichier
 
 -un trigger possède un nom long et une bibliothèque
 
 -on peut associer un trigger à la lecture (peut-elle avoir lieu ?)
 
 -l'écriture des triggers peut se faire en SQL PSM (L4G)
 
    dans ce dernier cas, - le trigger peut-être associé à la modification
                            d'un champ.
 
                         - vous pouvez indiquer des conditions au lancement
                            du trigger.
 
                         - il peut-être lancé à chaque ligne modifée ou bien
                             une fois par instruction (UPDATE par ex.).
 


|    Changer de couleur
 
 un trigger s'identifie maintenant par un nom long et une bibliothèque
  de trigger (ce qui n'est pas la bibliothèque du programme)
 
 voyons la commande ADDPFTRG :
 
                    Ajouter déclencheur fich phys (ADDPFTRG) 
 
 Fichier physique . . . . . . . .                 Nom
   Bibliothèque . . . . . . . . .     *LIBL       Nom, *LIBL, *CURLIB
 Moment de déclenchement  . . . .                 *BEFORE, *AFTER
 Evénement de déclenchement . . .                 *INSERT, *DELETE, *UPDATE.
 Programme  . . . . . . . . . . .                 Nom
   Bibliothèque . . . . . . . . .     *LIBL       Nom, *LIBL, *CURLIB
 Remplacer déclencheur  . . . . .   *NO           *NO, *YES
 Déclencheur  . . . . . . . . . .   *GEN                                    
                                                                            
                                                                            
                                                                            
                                                                            
                                                                            
  Bibliothèque du déclencheur  . .   *FILE         Nom, *FILE, *CURLIB


|    Changer de couleur
 
 le paramètre Déclencheur (TRG) permet d'indiquer un nom de trigger, ce
  dernier ne pouvant plus être identifié par le couple moment/évenement.
 
  le nom ne doit pas dépasser 128 c. (ou 258 entre guillemets)
 
  les triggers existants en V4 sont nommés
 
     QSYS_TRIG_nombib_nomfichier_00001
 
     les noms de bibliothèque et de fichier étant complémentés à 10 par "_"
 
 le paramètre Bibliothèque (TRGLIB) indique la bibliothèque du trigger
  (et non la bibliothèque du pgm lui même qui est fournie dans PGM)
 
  la valeur *FILE attribue le nom de la bibliothèque du fichier,
   *CURLIB, la bibliothèque en cours.
 
 
 c'est le couple  TRGLIB/TRG qui identifie un trigger de manière unique.
  (ATTENTION, l'unicité se faisant sur tout le système)
 


|    Changer de couleur
 
 désactivation d'un trigger :
 
 CHGPFTRG  FILE(QGPL/TEST) TRG(TRG_TEST_READ) TRGLIB(*FILE)
 
           STATE(*ENABLED | *DISABLED)
 
 à l'état *DISABLED le trigger n'est plus appellé lors des E/S.
 
 la commande DSPFD indique l'état actuel
 
............................................................................
:Description de déclencheur                                                :
:                                                                          :
: Nom de déclencheur. . . . . . . . . . . . . : TRG        QSYS_TRIG_BDVIN_:
:       ____MA_CAVE____000001                                              :
:   Bibliothèque de déclencheur . . . . . . . :            BDVIN9          :
:   Etat du déclencheur . . . . . . . . . . . : STATE      *ENABLED        :
:   Etat du déclencheur . . . . . . . . . . . :            *OPERATIVE      :
:..........................................................................:
 
 *operative indique un trigger associé à un fichier avec au moins un membre.


|    Changer de couleur
 
 un trigger peut-être associé à l'ordre de lecture :
 (trigger système [non SQL] uniquement.)
 
 ADDPFTRG ...   TRGTIME(*AFTER) TRGEVENT(*READ) ALWREPCHG(*NO)
 
  on intercepte la lecture après, uniquement.
   mais c'est le buffer avant qu'il faut traiter (???)
 
  les évenements sont codés :  1 = insert  2 = delete
                               3 = update  4 = read
  ........................................................................
  : IL FAUT IMPERATIVEMENT :                                             :
  :    - utiliser ces codes, les déplacements sont TOUJOURS renseignés   :
  :    - utiliser les déplacements (offsets), la position des données    :
  :       a été modifiée sur cette version.                              :
  :......................................................................:
 
   on ne peut pas sustituer des données dans le buffer [ALWREPCHG(*NO).]
 
  on peut empecher la lecture, par l'envoi d'un message d'erreur.
 


|    Changer de couleur
 
 et enfin la crétation de triggers en SQL :
 
                                                    --- BEFORE----
 CREATE TRIGGER --nom-trigger----------------------!              !------>
                                                    ---AFTER------
 
       ---INSERT-----------------------------------
       !                                          !
 >-----!--DELETE----------------------------------!-----REFERENCING--->
       !                                          !
       !--UPDATE----------------------------------!
                !                      !
                !-- OF colonne --------!
 
      ----OLD ROW -- AS ---nom-correlation-------
      !                                         !
      !---NEW ROW -- AS ---nom correlation------!   -FOR EACH STATEMENT-
 >----!                                         !---!                   !->
      !---OLD TABLE -- AS --identifiant---------!   --- FOR EACH ROW----
      !                                         !
      !---NEW TABLE -- AS --identifiant---------!


|    Changer de couleur
 
 
                                           --MODE DB2ROW---
>---- SET OPTION (option de compilation)--!                !-------->
                                           --MODE DB2SQL---
 
>-----WHEN (condition d'exécution du trigger)---------------->
 
>-BEGIN
  ...
(corps du trigger )
  ...
  END
 
quelques explications :
 
 + BEFORE ne peut pas contenir des ordres INSERT, UPDATE, DELETE
          mais peut modifier les variables de la table par SET.
 
   AFTER peut contenir des ordres INSERT, UPDATE, DELETE sur d'autres tables
 
 


|    Changer de couleur
 
 + INSERT | DELETE | UPDATE représentent l'événement associé(READ non admis)
 
   UPDATE OF "colonne" permet de ne déclencher le trigger que si "colonne"
     a été modifiée.
 
 + REFERENCING OLD ROW | NEW ROW
 
               OLD n'est valide qu'avec UPDATE, DELETE
               NEW   "     "       "    UPDATE, INSERT
 
 
    exemple :  REFERENCING OLD ROW AS avant NEW ROW AS apres
 
                puis dans le code :
 
                  IF apres.prix > avant.prix ....
 
 
  OLD ROW, NEW ROW ne peuvent pas être utilisés avec l'option
    FOR EACH STATEMENT.
 


|    Changer de couleur
 
exemple, lors d'une modification si le prix actuel est < au prix d'achat
  il doit prendre au moins la valeur du nouveau prix d'achat :
 
 ........................................................................
 :                                                                      :
 : CREATE TRIGGER  MAJ_PRIX BEFORE UPDATE OF CAV_PRXACTUEL              :
 :                           ON BDVIN/MA_CAVE                           :
 :  REFERENCING NEW ROW AS NOUVEAU                                      :
 :  FOR EACH ROW MODE DB2ROW                                            :
 :                                                                      :
 : BEGIN                                                                :
 :                                                                      :
 :  IF NOUVEAU.CAV_PRXACTUEL < NOUVEAU.CAV_PRIX THEN                    :
 :      SET NOUVEAU.CAV_PRXACTUEL = NOUVEAU.CAV_PRIX ;                  :
 :  END IF;                                                             :
 :                                                                      :
 : END                                                                  :
 :                                                                      :
 :......................................................................:
 
 


|    Changer de couleur
 
 
 + REFERENCING OLD TABLE | NEW TABLE
 
                OLD n'est valide qu'avec UPDATE, DELETE
                NEW   "     "       "    UPDATE, INSERT
 
 
     OLD table représente une table temporaire contenant l'ensemble
         des enregistrements modifiés ou supprimés.
         (les valeurs sont celles avant l'instruction d'origine)
 
     NEW table représente une table temporaire contenant l'ensemble
         des enregistrements insérés ou supprimés.
         (les valeurs sont celles après l'instruction d'origine et après
           l'appel du(des) trigger(s) BEFORE)
 
    ces deux options ne peuvent être utilisées qu'avec :
      le mode DB2SQL, et le moment AFTER.
      (FOR EACH ROW ou FOR EACH STATEMENT)
 
 


|    Changer de couleur
exemple, on trace cumul des prix modifiés :
.......................................................................
: CREATE TRIGGER  VIN_CUMUL  AFTER UPDATE OF CAV_PRIX                 :
:                            ON BDVIN9/MA_CAVE                        :
: REFERENCING OLD TABLE AS OCAVE                                      :
:           NEW TABLE AS NCAVE                                        :
: FOR EACH STATEMENT MODE DB2SQL                                      :
:                                                                     :
:  BEGIN                                                              :
:   DECLARE AV_CUMUL DEC(11, 2);                                      :
:   DECLARE AP_CUMUL DEC(11, 2);                                      :
:                                                                     :
:   SELECT SUM(CAV_PRIX) INTO AV_CUMUL FROM OCAVE  ;                  :
:   SELECT SUM(CAV_PRIX) INTO AP_CUMUL FROM NCAVE  ;                  :
:                                                                     :
:   INSERT INTO AF4TEST/CUMUL VALUES(NOW() , AV_CUMUL, AP_CUMUL) ;    :
:  END                                                                :
:.....................................................................:
 suite à un ordre : update bdvin9/ma_cave set cav_prix = cav_prix * 1,5
 
  QUAND                          AVANT_CUMUL      APRES_CUMUL  
  2001-08-23-14.25.20.181728          205,95           308,92


|    Changer de couleur
 
 + FOR EACH ROW | EACH STATEMENT
 
   FOR EACH ROW le trigger est appellé une fois par ligne
 
       cas des contrôles, des mise à jour de champs, des traces ...
 
 
   FOR EACH STATEMENT le trigger est appellé une fois par instruction.
 
       cas de recalcul automatique de cumuls, etc...
 
     ATTENTION : le trigger est appellé même si aucune ligne n'est impactée
 
 + MODE DB2ROW , DB2SQL
 
   MODE DB2ROW, l'appel a lieu à chaque ligne modifiée,
 
                BEFORE ET AFTER sont valides,
 
                FOR EACH STATEMENT et l'utilisation de OLD TABLE/NEW TABLE
                  ne sont PAS admis.


|    Changer de couleur
 
   MODE DB2SQL, l'appel a lieu à la fin de l'instruction,
 
                seul AFTER est valide,
 
                FOR EACH STATEMENT et l'utilisation de OLD TABLE/NEW TABLE
                  SONT admis.
 
   les valeurs reçues sont bien celles utilisée lors de la transaction,
    la grande différence est que le trigger n'est appellé que si l'ordre
    SQL va jusqu'au bout.
 
 exemple : 
 
   mise à jour d'un fichier dont la dernière ligne est verrouillée par un
    autre JOB, le trigger écrit dans une table afin de conserver une trace.
 
   avec MODE DB2ROW le trigger est appellé (n - 1 ) fois,  n étant le
    nombre d'enregistrements à modifier.
 
   avec MODE DB2SQL le trigger n'est pas activé (fichier trace vide).
 


|    Changer de couleur
 
 + SET OPTIONS
 
       options du compilateur (C), particulièrement DBGVIEW = *SOURCE
 
 + WHEN (condition)
 
       condition quant à l'appel du trigger
 
 exemple :
 ........................................................................
 :                                                                      :
 : CREATE TRIGGER  MAJ_PRIX BEFORE UPDATE OF CAV_PRXACTUEL              :
 :                           ON BDVIN/MA_CAVE                           :
 :  REFERENCING NEW ROW AS NOUVEAU                                      :
 :  FOR EACH ROW MODE DB2ROW                                            :
 :  WHEN (NOUVEAU.CAV_PRXACTUEL < NOUVEAU.CAV_PRIX)                     :
 :                                                                      :
 : BEGIN                                                                :
 :      SET NOUVEAU.CAV_PRXACTUEL = NOUVEAU.CAV_PRIX ;                  :
 : END                                                                  :
 :......................................................................:


|    Changer de couleur
 
 corps du triggers, (voir les procédures cataloguées)
 
 BEGIN (ATOMIC | NON ATOMIC)
 
  déclaration de variables                          ;
  déclaration de curseurs                           ;
  déclaration de handler (gestion des exceptions)   ;
 
 
 instructions SQL (INSERT, UPDATE, DELETE, FETCH)   ;
 
 instructions de structuration
 
                  (IF, WHILE, LOOP)                 ;
 
 assignation de variables (SET ou VALUES)           ;
 
 génération d'une exception (SIGNAL , RESIGNAL)     ;
 
 
 END


|    Changer de couleur
 
 Quelques nouveautés en ce qui conserne la gestion des exceptions :
 
 rappel, une erreur se prévoit par
 
    DECLARE nom_condition CONDITION FOR SQLSTATE 'n°'
 
 et/ou                                                  --SQLSTATE 'n°'--
              ---CONTINUE-------                       !- nom-condition--!
    DECLARE  !------------EXIT--!-- HANDLER FOR -------!- SQLEXCEPTION---!->
              -- UNDO-----------                       !- SQL WARNING--- !
                                                        - NOT FOUND -----
 
>-- instruction(s) SQL à exécuter en cas d'erreur-- ;
 
 
 avec les triggers :
 
   UNDO n'est pas valide, utilisez ATOMIC (trigger complet ou rien)
     ou bien gérer le COMMIT/ROLLBACK
 
 


|    Changer de couleur
 
 GET DIAGNOSTIC variable ROW COUNT : retourne le nombre de lignes affectées
  "     "         "      RETURN STATUS "       "  dernier code status
 
 
 pour signaler un code retour, terminer la procédure par RETURN n°
 
       RETURN 0
   ou
       RETURN -200
 
 
 pour signaler une erreur, utilisez SIGNAL (ordre de la V4)
 
   SIGNAL SQLSTATE 'n°'---------------------------------------- -
                         !--- SET MESSAGE_TEXT 'votre-texte'--!
 
   RESIGNAL  doit être placé dans un condition handler
 
   (sans paramètres, il génère l'erreur qu'il a lui-même recu.)
 
 


|    Changer de couleur
SQLSTATE est ammené à remplacer SQLCOD/SQLCODE (orientation ISO)
 
 SQLSTATE est composé de CINQ caractères (chiffres ou lettres)
 
 les deux premiers caractères représentent la classe,
  les codes commencant par 0 à 6 et A à H sont réservés
 
  00 : Success (terminé normalement)
  01 : Warning (message d'attention), donne SQLCOD = +438)
  02 : No DATA (l'équivalent de SQLCOD = 100)
  03 à ZZ : erreur, donne SQLCOD = -438.
   (38 signale la fin anormale, d'une fonction par exemple)
 
  le troisième caractère représente la sous classe.
  les sous classes de '0' à 'H' sont réservés, I à Z est libre.
 
 les codes commencant par 7,8,9 et I à Z sont libres,les sous classes aussi.
 ce qui fait que vous devez utiliser :
 - '00000' quand tout va bien.
 - '01Hxx' pour signaler un WARNING.
 - '38Ixx' à '38Zxx' pour signaler vos erreurs dans vos fonctions/triggers.
 - un code disponible dans les autres cas.


|    Changer de couleur
 
Sinon, voici un rappel succinct des ordres de structuration du SQL PSM :
 
IF test  THEN  instruction ELSEIF instruction ELSE instruction END IF;
 
CASE WHEN ....WHEN ... ELSE ...  END CASE;   (comme dans le SELECT)
 
LEAVE label;   sortie de la boucle qui s'appelle "label"
 
GOTO  label;   aller à l'instruction qui s'appelle "label"
 
 
label: LOOP instructions END LOOP;
 
label: WHILE (condition) instructions END WHILE;
 
label: REPEAT instructions UNTIL (condition) END REPEAT;
 
FOR  nom AS C1 CURSOR FOR select .. from .. where ..
 instructions
END FOR;
 





©AF400