Bienvenidos a Iseries Venezuela

Las mejores prácticas, recursos, tips, enlaces, videos y artículos para informáticos relacionados con el Iseries y el As/400 lenguajes de programación RPG, ILE RPG y SQL.

The best practices, resources, tips, links, videoes and articles for computer related to the Iseries and the As/400 languages of programming RPG, ILE RPG and SQL.
Showing posts with label Programación CL. Show all posts
Showing posts with label Programación CL. Show all posts

Thursday, October 30, 2014

¿Qué Sabes Sobre Monitor Message MONMSG?

Capturando los mensajes de Error














El comando MONMSG nos ofrece la posibilidad de monitorear los mensajes de error que emite el sistema operativo ante un error de ejecución del programa CLP.

En caso de error, el  programador es quien debe decidir e indicar al sistema operativo la acción a seguir. Si el programador no monitorea el mensaje de error e indica que instrucciones deben ejecutarse en caso de falla, el programa detiene su ejecución.
He visto varios códigos de programas en CLP que colocan el MONMSG antes y después de la instrucción a monitorear ante la incertidumbre de no saber realmente donde debe colocarse.

El MONMSG debe colocarse  en dos eventos estratégicos dentro de un CLP

1.- Al principio del programa.

El objetivo fundamental de colocar el  Monmsg al principio del programa es la de capturar cualquier error imprevisto en la ejecución de todo el programa. 

 -Aquello que se me haya olvidado monitorear en las siguientes instrucciones debe caer en esta “RED” que atrape el error no previsto por mí.-

Para ello utilizamos en general, los mensajes de error CPF0000 y MCH0000
Cabe destacar en este punto que la mayoría de los programadores coloca los mensajes CPF0000 y CPF9999 de manera automática. Parecieran interpretar que con colocar desde el 00000 hasta el 9999 abarca todo el rango de mensajes de tipo CPFXXXX.

Cuando queremos monitorear todos los mensajes de error de una categoría de mensajes es suficiente con colocar las tres primeras letras que identifican la categoría seguidas de ceros. Esto permite capturar todos los mensajes de error de esa categoría. En este ejemplo es suficiente con colocar CPF0000 y no es necesario colocar el mensaje CPF9999 en el monmsg ya que el CPF9999 esta siendo incluido al colocar el mensaje CPF0000.

Lo mismo sucede con MCH0000. Se monitorean automáticamente todos los mensajes de error MCHXXXX.
También podemos monitorear un subconjunto de mensajes en forma global. Por ejemplo, si queremos monitorear los mensajes que comienzan por CPF98XX con rellenar con ceros las 'X' se incluyen todos los mensajes de esa clclasificación. Con colocar: CPF9800 en el MONMSG, es suficiente. 

Con el comando WRKMSGF *all se puede obtener la lista de archivos de mensajes creados en el equipo. Lo archivos de mensajes donde residen los mensajes que genera el sistema operativo comienzan con la letra “Q”. Cada uno de estos archivos de mensajes representa una categoría de errores a monitorear.
El comando WRKMSGF permite ver, a través de varias opciones, la descripción detallada de los mensajes que están registrados en cada archivo de mensajes manejado por el sistema operativo.

Cuando colocamos un MONMSG como primer comando de un programa  CLP es conveniente incluir un EXEC que realiza un GOTO a una etiqueta en la cual se ejecutarán las instrucciones que el programador indique en caso de error.

 Si monitoreamos el error pero no indicamos ninguna acción a seguir, podemos deducir erróneamente que el programa se ejecutó correctamente. La verdad es que nuestro propio monitoreo puede ser “cuchillo para nuestra garganta” porque no fuimos avisados a tiempo de una interrupción inesperada que impidió la conclusión del programa.

En la etiqueta referida en el GOTO podemos colocar un SNDMSG a nuestra cola de usuarios, a la consola, a la cola de mensajes del operador o llamar a un programa que grabe un archivo de errores dando aviso por fecha, hora, proceso y usuario de la caída del programa, por ejemplo. Lo importante es: ¡hacer algo por favor¡


Ejemplo de programa CLP

Sunday, August 14, 2011

Monitoreo de errores en programas CLP




Usualmente el comando MONMSG es utilizado por la mayoría de los programadores para colocar códigos de error conocidos y predecibles. Por ejemplo, en un programa CLP al agregar una librería en la lista de librería y la librería puede que ya exista en la lista, entonces monitoreamos el error CPF2103, para que el programa no se detenga y continúe el proceso.

Es posible la existencia de procesos cuyos errores no son predecibles a simple vista por el programdor y que pueden detener el programa, quedando a expensas de la acción del operador en ese momento. Una vez producido el error y abortado el programa, es necesario revisar el log del job que arroja el sistema operativo para descubrir cual fue el error. El proceso de búsqueda de errores puede volverse engorroso y largo y en algunos casos cuando el log del sistema o los listados del job son eliminados de un día para otro (en forma manual o automática) se pierde el rastro del error.

La siguiente rutina permite capturar el Identificador de mensaje y su descripción, para aquellos mensajes que emite el sistema operativo en caso de errores inesperados para el programador. Se está provocando un error a manera de ejemplo con el comando RMVM (remover miembro de un archivo) en una librería y archivos ficticios.
El Id del error y su texto son capturados en variables del programa y pueden ser grabado posteriormente en un archivo físico de log de errores creado por el programador para su posterior revisión.

Monitoreo de Mensajes de error


Autor: Ing. Liliana Suárez.


Si te pareció interesante el artículo reenvíalo a un amigo, haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.


Monday, May 3, 2010

Subrutinas en un programa CL













Es posible manejar subrutinas en un programa CL.
Las subrutinas deben ser colocadas antes del ENDPGM del programa principal.
Los comandos SUBR y ENDSUBR, delimitan el principio y el fin de la rutina.
PGM

Declaraciones: DCL, DCLF, DCLPRCOPT
dcl   &valor    *int    4

Código del programa principal
…
…
…

SUBR SUBR (Rutina1)
Código de la rutina 1
ENDSUBR

SUBR SUBR (Rutina2)
Código de la rutina 2
ENDSUBR rtnval(&valor)

ENDPGM

El comando ENDSUBR tiene un parámetro opcional RTNVAL  que retorna un valor entero de 4 posiciones. Puede manejarse este valor a conveniencia. Monitorear un mensaje de error en las rutinas y colocar el valor de RTNVAL  Cero o en uno, podría indicar si fue o no exitosa la ejecución de la rutina y de acuerdo a ello proceder a las instrucciones convenientes en el programa principal.
Para llamar a una subrutina se utiliza el comando:   callsubr subr(RUTINA1) rtnval(&VALOR)
Como se observa el comando callsubr tiene dos parámetros: el nombre de la rutina y el valor de retorno.
Una subrutina regresa a “quien la llamó” al ejecutar el comando ENDSUBR, sin embargo si desea que por alguna condición particular se suspenda la ejecución de la rutina antes, entonces se puede utilizar la instrucción: RTNSUBR que tiene el mismo parámetro opcional RTNVAL que tiene el ENDSUBR.
Las subrutinas no pueden declararse una dentro de otra (anidarse). Sin embargo, las subrutinas pueden llamar a otras subrutinas.

Cada invocación de una subrutina genera una entrada a la pila de llamadas que puede alcanzar hasta 9999 niveles. Puede utilizarse el comando DCLPRCOPT  SUBRSTACK(100)para establecer el nivel máximo de alcance en la pila de llamadas. Si se establece un límite de llamadas y la ejecución del programa excede ese límite se generará un mensaje de error. CPF0822 ‘Overflow en la pila de llamadas’. En el ejemplo se colocamos 100 entradas en la pila de llamadas.
El comando DCLPRCOPT debe colocarse una sola vez en el CLP, en la sección del programa donde se declaran las variables y los archivos.




Autor: Ing. Liliana Suárez.

Si te pareció interesante el artículo reenvíalo a un amigo, haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.

Monday, February 22, 2010

Declaración múltiple de un archivo en un CLP.












Es posible manejar múltiples instancias de un mismo archivo en un CLP. El límite de instancias es cinco. Es decir, podemos declarar cinco veces el mismo archivo en un programa CLP indicando distintos OPNID en sus declaraciones respectivas.

En el código que muestro a continuación pueden ver el mismo archivo declarado dos veces con distinto OPNID.

Cuando se va a leer información de un archivo es necesario realizar un OPNDBF antes del comando de lectura RCVF. El OPNDBF debe tener especificado el OPNID que identifica la instancia del archivo que va a ser aperturado.
El código de ejemplo que les presento a continuación trata de un programa que maneja

   Inicio:      PGM        

/*El mismo archivo declarado dos veces con distintos OPNID */
                                                                             
DCLF       FILE(LIBRERIA/ABAPF004) RCDFMT(ABARC004) +                                           
     OPNID(ABAPF)                                                                          
 DCLF       FILE/(LIBRERIA/ABAPF004) RCDFMT(ABARC004) +                                           
     OPNID(ABAnue) 
                                                                       
  OPNDBF     FILE(LIBRERIA/ABAPF004) OPTION(*ALL) +                                               
  MBR(*FIRST) OPNID(ABAPF) ACCPTH(*FILE)     
                                         
   RCVF       RCDFMT(ABARC004) OPNID(ABAPF)                                                           
   CLOF       OPNID(ABAPF)      
   ADDPFM     FILE(LIBRERIA/ABAPF004) MBR(NUEVO) +                                                  
   SHARE(*YES)                                                                            

   CPYF       FROMFILE(LIBRERIA/ABAPF004) +                                                            
                 TOFILE(LIBRERIA/ABAPF004) TOMBR(NUEVO) +                                             
                  MBROPT(*ADD) FROMRCD(1) TORCD(1)                                                       
                                                                                                                       
   OPNDBF     FILE(LIBRERIA/ABAPF004) OPTION(*ALL) +                                                 
                      MBR(nuevo) OPNID(abanue) ACCPTH(*FILE)                                                 
                                                                                                                       
   OVRDBF     FILE(ABAPF004) TOFILE(LIBRERIA/ABAPF004) +                                             
                      MBR(NUEVO) POSITION(*START) SHARE(*YES)                                                
                                                                                                                       
     RCVF       RCDFMT(ABARC004) OPNID(ABANUE)    
                                                      
     MONMSG     MSGID(CPF0864) EXEC(GOTO FIN)     
                                            
                                                                                          
     CLOF       OPNID(ABAnue) 

   FIN: ENDPGM  

Autor: Ing. Liliana Suárez.

Si te pareció interesante el artículo reenvíalo a un amigo, haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.


Wednesday, March 18, 2009

SENTENCIAS DEL FLUJO DE CONTROL EN LOS CLP











Antes del Release V5R3 del Iseries, era imprescindible el uso del GOTO para generar lazos iterativos, bucles o ciclos de repetición. A partir del la versión V5R3 se introducen sentencias que permiten eliminar el uso del GOTO y desarrollar una programación con el uso de sentencias asociadas al concepto de Programación Estructurada. A continuación los nuevos comandos que permiten el Flujo de control en los CLP

• Nuevos Comandos CLP


----------------------

DOUNTIL

• Evalúa la condición al final del lazo

Ejemplo:

DOUNTIL (&NUM *EQ 20)

CHGVAR var(&NUM) Value(&NUM + 1)

END


------------------------------------

DOWHILE

• Evalúa la condición al principio del lazo

Ejemplo:

DOWHILE (&NUM *LT 20)

Chgvar var(&Num) Value(&Num + 1)

ENDDO


------------------------------

DOFOR

• Evalúa la condición al principio del lazo
• Var(&num) debe ser tipo *Int (integer)
• From/To pueden ser Integer, expresiones o variables.
• By() debe ser constante integer.


CHGVAR var(&NUMB) Value(0)

DOFOR VAR(&NUM) FROM(9) TO(13) BY(1)

CHGVAR var(&NUMB) Value(&NUMB + &NUM)

ENDDO
/* &NUMB = 55 después de ejecutar el DOFOR cuatro veces.


-------------------


SELECT (with WHEN and OTHERWISE)

• La Sentencia SELECT Inicia un grupo de comandos
• ENDSELECT Finaliza el grupo de comandos
• El grupo debe tener al menos una sentencia WHEN
• La sentencia OTHERWISE es opcional


SELECT

WHEN (&LogicaL)

WHEN (&NUM *GT 0) THEN (CHGVAR
&NUM 0)

WHEN (&NUM *GT 10) (DOUNTIL (&NUM
*EQ 0))

CHGVAR &NUM (&NUM - 1)
ENDDO

OTHERWISE (CHGVAR &LogicaL ’0’)

ENDSELECT


----------------------------------

ITERATE


• A través de etiquetas, permite saltar hacia otros lazos de iteración
• Por omisión permanece en el lazo donde se encuentra
• Pasa el control al final del lazo y verifica la condición.

Se permite dentro de un ciclo de iteración
– DOWHILE
– DOUNTIL
– DOFOR

CICLO1:
CICLO2: DOWHILE &LGL
CICLO3: DOFOR &INT FROM(0) TO(99)

IF (&NUMA *EQ 500) THEN (ITERATE CICLO1)
/* No procesa si NUMA=500 */

IF (&NUMA *GT 500) ITERATE
/* No procesa si NUMA>500 por omisión va a CICLO3*/
ENDDO

IF (&NUMA *LT 500) (ITERATE CICLO1)
/* No procesa si NUMA < 500 */ ENDDO


---------------------------

LEAVE


• A través de etiquetas, permite saltar hacia otros lazos de iteración
• Por omisión permanece en el lazo donde se encuentra
• Pasa el control a la instrucción que esté después del final del lazo

Se permite dentro de un ciclo de iteración
– DOWHILE
– DOUNTIL
– DOFOR

CICLO1:
CICLO2: DOWHILE &LGL
CICLO3: DOFOR &INT FROM(0) TO(99)

IF (&NUMA *EQ 500) THEN (LEAVE CICLO1)
/* No procesa si NUMA=500 */

IF (&NUMA *GT 500) LEAVE
/* No procesa si NUMA>500 salta a: IF Numa *Lt 500*/
ENDDO

IF (&NUMA *LT 500) (LEAVE CICLO1)
/* No procesa si NUMA < 500 */ ENDDO




Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.


Autor:  Ing. Liliana Suárez

Sunday, March 15, 2009

¿Es posible Hacer un Chain en un programa CL?












Cuando estamos programando un CLP, a veces nos encontramos en la necesidad de detectar si un registro con determinados valores en su clave, existe en la base de datos y dependiendo del resultado de la búsqueda tomamos una acción u otra.

Hay varias opciones para obtener un resultado, algunas son más felices que otras en términos de eficiencia y programación:

1.-Leer todo el archivo y preguntar si el valor de un campo corresponde al valor que estamos buscando en el archivo.
Esto consume mucho tiempo de respuesta.


2.-Llamar a un programa en RPG pasándole el valor como parámetro para que el Programa RPG realice el chain y nos devuelva en otro parámetro la respuesta de si existe o no existe el registro en el archivo. Esto implica un call cada vez que se entra al programa CLP

3.-Utilizar Opnqryf y leer los resultados que arroja. Es mas lento por la generación de una tabla de lectura intermedia.

4.-Realizar un ovrdbf especificando la clave de búsqueda y monitoreando el mensaje de excepción. Esta es la opción más eficiente. A continuación un ejemplo:

PGM
DCL VAR(&USER) TYPE(*CHAR) LEN(10)
DCLF FILE(TABLAUSER)
/* Obtiene el usuario actual */
RTVSYSVAL SYSVAL(QUSER) RTNVAR(&USER)

OVRDBF FILE(TABLAUSER) POSITION(*KEY 1 FMT1 &USER)
RCVF

/* SI ES FIN DE ARCHIVO O NO ENCUENTRA LA CLAVE DE BUSQUEDA */
/* Finaliza el programa*/
MONMSG MSGID(CPF0000) EXEC(GOTO CMDLBL(FINPGM))
/* Si el Usuario está en el archivo */

IF (&USER *EQ &NOMBRE) +
THEN(DO) /* USUARIO SI ESTA EN LA TABLA*/
GOTO CMDLBL(PROCESAR)
ENDDO


PROCESAR: CALL PGM(PROCUSER)
FINPGM: ENDPGM


Esta última opción es la mas eficiente ya que consume menos tiempo de procesamiento y el código es mas directo y fácil de seguir para cualquier programador.

Se explica el comando Ovrdbf con estos nuevos parámetros:

OVRDBF FILE(TABLAUSER) POSITION(*KEY 1 FMT1 &USER)

Los valores del parámetro POSITION se interpretan de la siguiente manera:

Posicionarse en:

A) *KEY = el primer registro del archivo TABLAUSER
B) FMT1 = con formato de registro FMT1
C) 1 = cuyo valor en el primer campo clave (1) sea igual al
valor de la variable &USER.

Al momento de ejecutar el RCVF, si no consigue ningún registro en el archivo que cumpla con esta condición entonces va a Fin de programa. Esta verificación se realiza utilizando el comando MONMSG para detectar si hay algún status de excepción.

1.- Además del valor *KEY existen otros valores que podemos emplear si necesitamos una búsqueda mas avanzada:


*KEYBE (key-before or equal): Si no hay registro en el archivo que haga match con el valor especificado en el ovrdbf, se selecciona el registro anterior con valor menor al especificado.
Esto es la combinación de dos comandos SETLL y READ

*KEY (key-equal): The registro identificado por los valores de búsqueda especificados en el programa es el registro que será retribuido en la lectura.
Esto es la combinación de SETLL y READE

*KEYAE (key-after or equal):
Si no hay registro en el archivo que haga match con el valor especificado en el ovrdbf, se selecciona el siguiente registro con valor mayor al especificado.
Esto es la combinación de dos comandos READE y SETGT

*KEYA (key-after):
El primer registro con un valor mayor al valor especificado en el programa será el registro retribuido en la lectura.
Esto es la combinación de dos comandos SETGT y READ

2.-Número de Campos clave en la búsqueda.

En el ejemplo colocamos un 1, pero podemos colocar otros valores de acuerdo a lo que necesitemos buscar en el archivo.

Si POSITION(*KEY 1 FMT1 A) es especificada, el primer registro en el archivo con formato de registro FMT1 que tiene su primer campo clave con valor ‘A’ es retribuido en la lectura. Si se especifica un valor cero (0) la búsqueda del valor ‘A’ se realizará en todos los campos clave del archivo.

Si especificamos un valor 2, por ejemplo estamos diciendo que busque el primer registro del archivo con valor ‘A’ en el segundo campo que constituye la clave del archivo.

El nombre del formato de registro puede ser omitido y podemos colocar *N para decirle que tome todos los formatos de registro del archivo

Tomando en cuenta estos últimos tips, el parámetro POSITION quedaría asi:

POSITION(*KEY 2 *N A)



Si te pareció interesante, reenvialo a un amigo haciendo click en el sobrecito que está al final del artículo. El conocimiento es valioso, compártelo.


Autor:  Ing. Liliana Suárez