iSeries DB2 y RPG. Como usar Triggers o desencadenantes.

3 Flares Twitter 1 Facebook 1 LinkedIn 0 Google+ 1 3 Flares ×

Un Trigger o desencadenante de una Base de Datos no es más que un proceso que se dispara ante algún evento configurado que ocurra en nuestro sistema. Básicamente, es una manera de decirle al sistema que cuando un registro de la Base de datos cambie, haga una llamada a un programa que nosotros especificamos y con el que podemos tratar los datos del registro modificado.

En el iSeries, la gestión de los triggers la tenemos dentro del menú CMDTRG, donde encontramos opciones para añadir un trigger, modificarlo, borrarlo o listar todos los triggers que estén definidos contra los ficheros de un biblioteca concreta. Hoy nos vamos a centrar en añadir triggers, las demás opciones son muy fácil de entender y realizar, así que las obviaré.

Para añadir un trigger basta usar la opción 1 del menú anterior o el mandato ADDPFTRG (añadir trigger de archivo físico). La configuración es bien sencilla, nos pregunta el archivo/biblioteca que queremos controlar, si el trigger se dispara antes o después de actualizar el registro, que evento lo desencadena (lectura, modificación, adición o borrado) y a que programa/biblioteca llamamos cuando se produzca el evento.

AddPfTrg

Hay que añadir un trigger por cada evento, no existe un *ALL, de manera que añadimos 1 para *INSERT, otro para *DELETE, etc….. Aunque el programa puede ser el mismo ya que podemos controlar que evento lo ha llamado.

Antes de activar un trigger debemos tener el programa generado, ya que si no la llamada nos dará error cada vez que alguien modifique un registro del archivo.

Veamos ahora como se diseña un programa llamado desde un trigger. Lo primero que tenemos que tener en cuenta son los parámetros de entrada. Todos los trigger llaman al programa indicado usando los mismos parámetros y que detallo a continuación….

D PARM1           DS          9999
D  FNAME                  1     10      *Nombre del Archivo que dispara el trigger
D  LNAME                 11     20      * Bliblioteca del Archivo
D  MNAME                 21     30      * Miembro del Archivo</pre>
D  TEVEN                 31     31      * Evento Activador (1, 2 o 3)
                                        *  '1' OPERACIÓN DE INSERCIÓN
                                        *  '2' OPERACIÓN DE SUPRESIÓN
                                        *  '3' OPERACIÓN DE ACTUALIZACIÓN
D  TTIME                 32     32      * Hora del Activador
                                        *  '1' DESPUÉS DE LA OPERACIÓN
                                        *  '2' ANTES DE LA OPERACIÓN
D  CMTLCK                33     33      * Nivel de Bloqueo de Compromiso
D  FILL1                 34     36      * Reservado
D  CCSID                 37     40B 0   * CCSID
D  FILL2                 41     48      * Reservado
D  OLDOFF                49     52B 0   * Desplazamiento al Reg Original
D  OLDLEN                53     56B 0   * Longitud del Registro Original
D  ONOFF                 57     60B 0   * Desplazamiento Bytes Nulos Reg Original
D  ONLEN                 61     64B 0   * Longitud de Correlacion de Bytes Nulos
D  NOFF                  65     68B 0   * Desplazamiento al nuevo registro
D  NEWLEN                69     72B 0   * Longitud Nuevo Registro
D  NNOFF                 73     76B 0   * Desplazamiento Bytes Nulos Reg Nuevo
D  NNLEN                 77     80B 0   * Longitud de Correlacion de Bytes Nulos
D  RESV3                 81     96      * Reservado
 *
D PARM2           DS
D  LENG                   1      4B 0
*---------------------------------------------------------------*
C     *ENTRY        PLIST
C                   PARM                    PARM1
C                   PARM                    PARM2

Con estos parámetros tenemos toda la información que necesitamos para actuar en caso de que se dispare un trigger, tenemos el archivo, miembro y biblioteca que estamos tratando, el evento que se está produciendo, como estaba el registro antes del evento y como está después de ocurrir.

Bien, pues ahora vamos a ver como tratamos esta información.
Yo, normalmete uso el mismo programa para un mismo grupo de archivos, por ejemplo todos los que tengan que ver con artículos, de esta manera simplifico el número de programas y lo tengo más controlado. El programa ILERPG que creemos debe empezar con las descripciones y parametros de entrada que hemos descrito antes, y a partir de ahí, podemos tratar la información como queramos, como en cualquier otro programa.

Primero deberíamos definir como estructuras de datos las definiciones de los registros de los archivos que vamos a tratar, para simplificar el uso de campos definidos externamente. Esto nos ahorra bastante código que escribir.

D REGART        E DS                  EXTNAME(ARTICU)
D REGATR        E DS                  EXTNAME(ARTATR)

Luego utilizaremos una sentencia SELECT para distinguir que fichero es el que estamos procesando, y dentro de él, extraeremos los datos del registro anterior y del registro actual.

Primero controlamos el evento con el campo TEVEN, si no es 2, es decir, no es borrado, recuperamos el registro nuevo a partir del parametro PARM1 con el inicio y la longitud que nos proporcionan. Una vez recuperada la cadena, la movemos a la estructura del registro para poder acceder a los campos del mismo.

Si el parametro TEVEN es 2, o sea, el evento desencadenante es un borrado, el campo de registro nuevo viene en blanco, por lo que debemos recuperar el registro anterior para saber que datos hemos suprimido. Obviamente, por la misma regla, cuando sea un 1 correspondiente al alta, no existe el registro anterior.

C                   SELECT
 *--------------------------------------------------------------*
C     FNAME         WHENEQ    'ARTICU'
*
C     TEVEN         IFNE      '2'
 * Recuperamos el registro Nuevo y lo dejamos en la estructura REGART
C                   Z-ADD     NOFF          X                 5 0
C                   ADD       1             X
C                   Z-ADD     NEWLEN        Y                 5 0
C     Y             SUBST     PARM1:X       REGART
 * Llamada al programa de actualización de archivos remotos
C                   CALL      'ACTARTCL'
C                   PARM                    TEVEN
C                   PARM                    REGArt
C                   ENDIF
 *
C                   ELSE
 * Recuperamos los datos del Registro eliminado
C                   Z-ADD     OLDOFF        X                 5 0
C                   ADD       1             X
C                   Z-ADD     OLDLEN        Y                 5 0
C     Y             SUBST     PARM1:X       REGArt
 * Llamada al programa de actualización de archivos remotos
C                   CALL      'ACTARTCL'
C                   PARM                    TEVEN
C                   PARM                    REGArt
 *
C                   ENDIF
 *--------------------------------------------------------------*
C     FNAME         WHENEQ    'ARTATR'
 *...................
C                   ENDSL
 *---------------------------------------------------------------*·········
C                   MOVEL     *ON           *INLR

Yo normalmente con los datos recuperados hago una llamada a otro programa que se ejecuta en Batch, de manera que si se produce algún error en el programa, el usuario no es interrumpido y lo controlo en la cola de trabajos correspondiente.

Debéis tener en cuenta que si un trigger está definido como que se ejecute con el valor *BEFORE, el cambio todavía no se ha producido en el archivo, por lo que tened cuidado con las pérdidas de información. Yo suelo usar siempre *AFTER, de esa manera me aseguro de que los datos siempre están actualizados.

Pero esto son consejos míos, el caso es que con toda esta información, ya podemos controlar lo que ha sucedido en el momento de dispararse el trigger. Incluso en el caso de una modificación, recuperar el registro antiguo y el nuevo y saber exactamente que campos se han modificado. A partir de aquí, lo que cada uno quiera o necesite hacer con ese registro.

JoBenCa

http://jobenca.es

Administrador y desarrollador de sistemas IBM System i y curioso de todo tipo de tecnología.

View more posts from this author
11 thoughts on “iSeries DB2 y RPG. Como usar Triggers o desencadenantes.
  1. Helar Salas

    Todo perfecto, pero si además se necesita captura el usuario que al acceder a la tabla hizo que el trigger se ejecute, ¿como lo hago?

     
    Reply
    1. JoBenCa

      Pues si no me equivoco el trabajo que se ejecuta con el trigger se hace con el mismo usuario por lo que puedes recuperarlo con QSYS/RTVJOBA USER(&USER)

       
      Reply
  2. Sandra

    Buenos dias, puedo tener varios triggers, para la misma tabla, con el mismo evento (insert, update, etc) y con el mismo Trigger time (*before, *after)? Pero que llame a diferentes programas, que ejecuten cosas diferentes? Gracias de antemano. Saludos.

     
    Reply
    1. JoBenCa

      Buenos días
      Puedes perfectamente tener varios triggers que se ejecuten en el mismo momento y llamen a programas diferentes. Solo ten en cuenta que al crearlos no cambies la opción sustituir desencadenante a *YES, eso haría que eliminase el anterior. Si lo dejas en *NO tendrás ambos triggers.
      Para comprobar los triggers que tienes activos puedes usar el mandato PRTTRGPGM

      Saludos

       
      Reply
  3. Yineth

    Hola, puedo identificar el nombre del programa que está realizando la actualización del archivo? gracias!!

     
    Reply
    1. JoBenCa

      Hola, pues realmente creo que no.
      en los parámetros que recibe el programa desencadenante vienen todo lo relativo al registro modificado, pero nada de quién lo modifica.
      en esta cuestión no puedo ayudarte.

       
      Reply
  4. Manuel Chaves

    Accesando la pila de llamadas puedes obtener el nombre del programa que generó el evento

     
    Reply
    1. JoBenCa

      Si, es una opción, pero se sale del trigger como tal.
      Tendrías que tener un programa que chequeara la pila de llamadas y ver cual es el último.

       
      Reply
  5. Nicolas

    Hola,

    Creé el programa del trigger en RPG ILE, la tabla la cree en DB2, está tabla tiene campos tanto carácter como decimal, en el primer parámetro del programa del trigger donde llega la información de la tabla solo me está mostrando bien los campos carácter, pero los campos decimales me los muestra con caracteres raros de esos que no son parte de nuestro teclado, me ayuda por favor, sabe por qué se puede dar este caso y como solucionarlo?

     
    Reply
    1. JoBenCa

      Hola, pues eso suele ocurrir porque el dato numérico en un archivo está empaquetado y su representación no se puede pasar a texto tal cual.
      Si ves en el ejemplo, yo creo un área de datos igual al registro del fichero
      D REGART E DS EXTNAME(ARTICU)

      Y luego recupero los datos del registro y lo muevo a este área. Entonces se convierten automáticamente los datos a su formato concreto.
      Depende del registro que quieras recuperar usas este código para extraer la cadena del triggers y moverla al registro.

      * Recuperamos el registro Nuevo y lo dejamos en la estructura REGART
      C Z-ADD NOFF X 5 0
      C ADD 1 X
      C Z-ADD NEWLEN Y 5 0
      C Y SUBST PARM1:X REGART

      Espero haberte servido de ayuda.
      Saludos

       
      Reply

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

3 Flares Twitter 1 Facebook 1 LinkedIn 0 Google+ 1 3 Flares ×