Cuando necesitemos compilar un programa Cobol con transacciones CICS, siempre podremos
recurrir al procedimiento estándar DFHYITVL en vez de crearnos nuestro
propio JCL de compilación. De esta forma nos ahorraremos todo el trabajo
requerido para la generación del módulo del objeto Cobol CICS.
El procedimiento estándar DFHYITVL es un proceso que incluye la compilación del objeto Cobol CICS y su posterior paso de linkedit para generar el módulo asociado. Asimismo, incluye la invocación a un precompilador que procederá a traducir todas las sentencias CICS incluidas en nuestro programa.
El contenido de DFHYITVL es el siguiente:
//DFHYITVL PROC SUFFIX=1$, Suffix for translator module
// INDEX='DFH320.CICS', Qualifier for CICS libraries
// PROGLIB='DFH320.CICS.SDFHLOAD', Name of o/p library
// DSCTLIB='DFH320.CICS.SDFHCOB', Private macro/dsect
// AD370HLQ='IGY410', Qualifier for AD/Cycle compiler
// LE370HLQ='CEE', Qualifier for LE/370 libraries
// OUTC=A, Class for print output
// REG=4M, Region size for all steps
// LNKPARM='LIST,XREF', Link edit parameters
// STUB='DFHEILID', Lked INC. for DFHELII
// LIB='SDFHSAMP', Library
// WORK=SYSDA Unit for work datasets
//TRN EXEC PGM=DFHECP&SUFFIX,
// PARM='COBOL2', @01C
// REGION=®
//STEPLIB DD DSN=&INDEX..SDFHLOAD,DISP=SHR
//SYSPRINT DD SYSOUT=&OUTC
//SYSPUNCH DD DSN=&&SYSCIN,
// DISP=(,PASS),UNIT=&WORK,
// DCB=BLKSIZE=400,
// SPACE=(400,(400,100))
//*
//COB EXEC PGM=IGYCRCTL,REGION=®,
// PARM='NODYNAM,LIB,OBJECT,RENT,RES,APOST,MAP,XREF'
//STEPLIB DD DSN=&AD370HLQ..SIGYCOMP,DISP=SHR
//SYSLIB DD DSN=&DSCTLIB,DISP=SHR
// DD DSN=&INDEX..SDFHCOB,DISP=SHR
// DD DSN=&INDEX..SDFHMAC,DISP=SHR
// DD DSN=&INDEX..SDFHSAMP,DISP=SHR
//SYSPRINT DD SYSOUT=&OUTC
//SYSIN DD DSN=&&SYSCIN,DISP=(OLD,DELETE)
//SYSLIN DD DSN=&&LOADSET,DISP=(MOD,PASS),
// UNIT=&WORK,SPACE=(80,(250,100))
//SYSUT1 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT2 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT3 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT4 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT5 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT6 DD UNIT=&WORK,SPACE=(460,(350,100))
//SYSUT7 DD UNIT=&WORK,SPACE=(460,(350,100))
//*
//COPYLINK EXEC PGM=IEBGENER,COND=(7,LT,COB)
//SYSUT1 DD DSN=&INDEX..&LIB(&STUB),DISP=SHR
//SYSUT2 DD DSN=&©LINK,DISP=(NEW,PASS),
// DCB=(LRECL=80,BLKSIZE=400,RECFM=FB),
// UNIT=&WORK,SPACE=(400,(20,20))
//SYSPRINT DD SYSOUT=&OUTC
//SYSIN DD DUMMY
//*
//LKED EXEC PGM=IEWL,REGION=®,
// PARM='&LNKPARM',COND=(5,LT,COB)
//SYSLIB DD DSN=&INDEX..SDFHLOAD,DISP=SHR
// DD DSN=&LE370HLQ..SCEELKED,DISP=SHR
//SYSLMOD DD DSN=&PROGLIB,DISP=SHR
//SYSUT1 DD UNIT=&WORK,DCB=BLKSIZE=1024,
// SPACE=(1024,(200,20))
//SYSPRINT DD SYSOUT=&OUTC
//SYSLIN DD DSN=&©LINK,DISP=(OLD,DELETE)
// DD DSN=&&LOADSET,DISP=(OLD,DELETE)
// DD DDNAME=SYSIN
Como vemos, el procedimiento se divide en 4 pasos:
1º) Traducción CICS: se ejecuta el precompilador CICS denominado DFHECP1$, que procederá a traducir las sentencias CICS que hayamos incluido en nuestro programa Cobol.
2º) Compilador Cobol: realiza la compilación estándar del objeto Cobol. Se trata del proceso IGYCRCTL que se usa para cualquier programa.
3º) Copiar DFHEILID: Crea una copia del objeto DFHEILID, de la librería DFH320.CICS.SDFHSAMP, para que sea usada por el paso de Linkedit.
4º) Linkedition: Se realiza el paso de linkedit del objeto Cobol y se genera la salida en el la librería indicada. En nuestra instalación, se trata de la librería DFH320.CICS.SDFHLOAD.
Con estos 4 pasos, el procedure realiza la compilación completa del programa Cobol que tiene incorporadas las sentencias CICS. Para incluir esta utilidad en nuestra propia compilación únicamente tendremos
que incorporar la ejecución de este procedimiento en nuestro JCL.
Finalmente recordar que las librerías incluidas en el DFHYITVL podrían
variar un poco en vuestro equipo, dependiendo de la instalación del
CICS.
Saludos.
Desarrollando en Cobol y Natural sobre Plataforma Mainframe
viernes, 20 de diciembre de 2013
miércoles, 18 de diciembre de 2013
Compilador de objetos Cobol con CICS
En ocasiones, tendremos necesidad de incluir invocaciones CICS en nuestros programas Cobol (por ejemplo, para el tratamiento de Mapas). En estos casos, no podremos recurrir al compilador estándar de objetos Cobol y tendremos que usar un procedimiento especial que tenga en cuenta las transacciones CICS.
Si incluimos una ejecución CICS en nuestro programa Cobol e intentamos compilar de forma estándar, el compilador nos devolverá un error. Esto es debido a que, en estos casos, tenemos que recurrir al procedimiento de compilación denominado DFHYITVL.
Por ejemplo, supongamos que elaboramos un programa Cobol en el que tenemos una invocación CICS a un Mapa del siguiente modo.
*
EXEC CICS
SEND MAP('JJ0004M')
MAPONLY
ERASE
NOHANDLE
END-EXEC.
*
En casos como estos tendremos que emplear un compilador que disponga de la ejecución correspondiente del procedure DFHYITVL. Por ejemplo, podría ser el siguiente.
//JJCOM4CL JOB (123),'COMPILADOR CICS',CLASS=A,MSGCLASS=A,
// MSGLEVEL=(1,1),NOTIFY=&SYSUID
//***************************************************
//* DFHYITVL - COMPILADOR DE OBJETOS COBOL CON CICS
//***************************************************
//JOBPROC JCLLIB ORDER=DFH320.CICS.SDFHPROC
//CICSCOB EXEC DFHYITVL,
// DSCTLIB=LIBPR.COPYS.JJ00, *LIBRERIA DE COPYS
// PROGLIB=LIBPR.MODULOS.JJ01 *LIBRERIA DE MODULOS
//* UBICACION DEL PROGRAMA CON CICS
//TRN.SYSIN DD DSN=LIBPR.FUENTES.JJ00(JJ0004CO),DISP=SHR
//* LIBRERIAS SYSLIB DE IEWL - DFHELII
//LKED.SYSLIB DD DSN=DFH320.CICS.SDFHLOAD,DISP=SHR
// DD DSN=CEE.SCEELKED,DISP=SHR
// DD DSN=LIBPR.MODULOS.JJ01,DISP=SHR
//LKED.SYSIN DD *
NAME JJ0004CO(R)
//
Como vemos, este compilador especial se compone de un único paso que invoca directamente al procedimiento DFHYITVL. Dicho procedure se encarga de realizar la compilación de los objetos Cobol que tengan transacciones CICS.
En este paso tenemos que especificar los siguientes datos:
1º) Cláusula JCLLIB: Tenemos que especificar la librería en la que se encuentra el objeto DFHYITVL. Esto variará en cada instalación. En nuestro caso, se trata de la librería DFH320.CICS.SDFHPROC.
//JOBPROC JCLLIB ORDER=DFH320.CICS.SDFHPROC
2º) Parámetro DSCTLIB: Esta es la librería en la que se encuentran las copys que se van a utilizar en nuestro programa Cobol.
// DSCTLIB=LIBPR.COPYS.JJ00, *LIBRERIA DE COPYS
3º) Parámetro PROGLIB: Se trata de la librería en la que será almacenado el módulo generado a partir de nuestro programa Cobol.
// PROGLIB=LIBPR.MODULOS.JJ01 *LIBRERIA DE MODULOS
4º) Parámetro SYSIN: Aquí especificaremos la librería en la que se encuentra el fuente de nuestro objeto Cobol.
//TRN.SYSIN DD DSN=LIBPR.FUENTES.JJ00(JJ0004CO),DISP=SHR
5º) Parámetro SYSLIB: aquí habrá que especificar, entre otras cosas, la librería en la que se encuentra el objeto IEWL, uno de los empleados en el procedure DFHYITVL. En nuestro caso, se trata de la librería DFH320.CICS.SDFHLOAD.
//LKED.SYSLIB DD DSN=DFH320.CICS.SDFHLOAD,DISP=SHR
// DD DSN=CEE.SCEELKED,DISP=SHR
// DD DSN=LIBPR.MODULOS.JJ01,DISP=SHR
6º) Por último, al final del compilador tendremos que incluir la cláusula SYSIN indicada en el ejemplo.
//LKED.SYSIN DD *
NAME JJ0004CO(R)
Si se realiza correctamente, no deberíamos tener ningún problema con la compilación de nuestro objeto. La mayor dificultad de este procedimiento es especificar correctamente las librerías en las que se encuentra cada cosa. Debido a que cada instalación es diferente, tendremos que perder algún tiempo en identificarlas pero, una vez superado ese paso inicial, el proceso no debería darnos ningún quebradero de cabeza adicional.
Pues nada, como siempre, esperamos haberos ayudado un poco a ir profundizando en vuestro conocimiento del entorno Cobol.
Saludos.
Si incluimos una ejecución CICS en nuestro programa Cobol e intentamos compilar de forma estándar, el compilador nos devolverá un error. Esto es debido a que, en estos casos, tenemos que recurrir al procedimiento de compilación denominado DFHYITVL.
Por ejemplo, supongamos que elaboramos un programa Cobol en el que tenemos una invocación CICS a un Mapa del siguiente modo.
*
EXEC CICS
SEND MAP('JJ0004M')
MAPONLY
ERASE
NOHANDLE
END-EXEC.
*
En casos como estos tendremos que emplear un compilador que disponga de la ejecución correspondiente del procedure DFHYITVL. Por ejemplo, podría ser el siguiente.
//JJCOM4CL JOB (123),'COMPILADOR CICS',CLASS=A,MSGCLASS=A,
// MSGLEVEL=(1,1),NOTIFY=&SYSUID
//***************************************************
//* DFHYITVL - COMPILADOR DE OBJETOS COBOL CON CICS
//***************************************************
//JOBPROC JCLLIB ORDER=DFH320.CICS.SDFHPROC
//CICSCOB EXEC DFHYITVL,
// DSCTLIB=LIBPR.COPYS.JJ00, *LIBRERIA DE COPYS
// PROGLIB=LIBPR.MODULOS.JJ01 *LIBRERIA DE MODULOS
//* UBICACION DEL PROGRAMA CON CICS
//TRN.SYSIN DD DSN=LIBPR.FUENTES.JJ00(JJ0004CO),DISP=SHR
//* LIBRERIAS SYSLIB DE IEWL - DFHELII
//LKED.SYSLIB DD DSN=DFH320.CICS.SDFHLOAD,DISP=SHR
// DD DSN=CEE.SCEELKED,DISP=SHR
// DD DSN=LIBPR.MODULOS.JJ01,DISP=SHR
//LKED.SYSIN DD *
NAME JJ0004CO(R)
//
Como vemos, este compilador especial se compone de un único paso que invoca directamente al procedimiento DFHYITVL. Dicho procedure se encarga de realizar la compilación de los objetos Cobol que tengan transacciones CICS.
En este paso tenemos que especificar los siguientes datos:
1º) Cláusula JCLLIB: Tenemos que especificar la librería en la que se encuentra el objeto DFHYITVL. Esto variará en cada instalación. En nuestro caso, se trata de la librería DFH320.CICS.SDFHPROC.
//JOBPROC JCLLIB ORDER=DFH320.CICS.SDFHPROC
2º) Parámetro DSCTLIB: Esta es la librería en la que se encuentran las copys que se van a utilizar en nuestro programa Cobol.
// DSCTLIB=LIBPR.COPYS.JJ00, *LIBRERIA DE COPYS
3º) Parámetro PROGLIB: Se trata de la librería en la que será almacenado el módulo generado a partir de nuestro programa Cobol.
// PROGLIB=LIBPR.MODULOS.JJ01 *LIBRERIA DE MODULOS
4º) Parámetro SYSIN: Aquí especificaremos la librería en la que se encuentra el fuente de nuestro objeto Cobol.
//TRN.SYSIN DD DSN=LIBPR.FUENTES.JJ00(JJ0004CO),DISP=SHR
5º) Parámetro SYSLIB: aquí habrá que especificar, entre otras cosas, la librería en la que se encuentra el objeto IEWL, uno de los empleados en el procedure DFHYITVL. En nuestro caso, se trata de la librería DFH320.CICS.SDFHLOAD.
//LKED.SYSLIB DD DSN=DFH320.CICS.SDFHLOAD,DISP=SHR
// DD DSN=CEE.SCEELKED,DISP=SHR
// DD DSN=LIBPR.MODULOS.JJ01,DISP=SHR
6º) Por último, al final del compilador tendremos que incluir la cláusula SYSIN indicada en el ejemplo.
//LKED.SYSIN DD *
NAME JJ0004CO(R)
Si se realiza correctamente, no deberíamos tener ningún problema con la compilación de nuestro objeto. La mayor dificultad de este procedimiento es especificar correctamente las librerías en las que se encuentra cada cosa. Debido a que cada instalación es diferente, tendremos que perder algún tiempo en identificarlas pero, una vez superado ese paso inicial, el proceso no debería darnos ningún quebradero de cabeza adicional.
Pues nada, como siempre, esperamos haberos ayudado un poco a ir profundizando en vuestro conocimiento del entorno Cobol.
Saludos.
viernes, 13 de diciembre de 2013
Procedimiento DFHMAPS para compilación de Mapas
Cuando necesitemos compilar un Mapset de Cobol, siempre podremos recurrir al procedimiento estándar DFHMAPS en vez de crearnos nuestro propio JCL de compilación. De esta forma nos ahorraremos todo el trabajo requerido para la generación de los Mapas Simbólico y Físico.
El procedimiento estándar DFHMAPS es un proceso que incluye la compilación de nuestros Mapas mediante el Ensamblador ASMA90, así como de todos los pasos necesarios para chequear si nuestro Mapset tiene algún problema en su estructura.
El contenido de DFHMAPS es el siguiente:
//DFHMAPS PROC INDEX='DFH320.CICS',
// MAPLIB='DFH320.CICS.SDFHLOAD',
// DSCTLIB='DFH320.CICS.SDFHMAC',
// MAPNAME=,
// A=,
// AMODE=31,
// RMODE=ANY,
// ASMBLR=ASMA90,
// REG=2048K,
// OUTC=A,
// WORK=SYSDA
//COPY EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=&OUTC
//SYSUT2 DD DSN=&&TEMPM,UNIT=&WORK,DISP=(,PASS),
// DCB=(RECFM=FB,LRECL=80,BLKSIZE=400),
// SPACE=(400,(50,50))
//SYSIN DD DUMMY
//* SYSUT1 DD * NEEDED FOR THE MAP SOURCE
//ASMMAP EXEC PGM=&ASMBLR,REGION=®,
//* NOLOAD CHANGED TO NOOBJECT
// PARM='SYSPARM(&A.MAP),DECK,NOOBJECT'
//SYSPRINT DD SYSOUT=&OUTC
//SYSLIB DD DSN=&INDEX..SDFHMAC,DISP=SHR
// DD DSN=SYS1.MACLIB,DISP=SHR
//SYSUT1 DD UNIT=&WORK,SPACE=(CYL,(5,5))
//SYSUT2 DD UNIT=&WORK,SPACE=(CYL,(5,5))
//SYSUT3 DD UNIT=&WORK,SPACE=(CYL,(5,5))
//SYSPUNCH DD DSN=&&MAP,DISP=(,PASS),UNIT=&WORK,
// DCB=(RECFM=FB,LRECL=80,BLKSIZE=400),
// SPACE=(400,(50,50))
//SYSIN DD DSN=&&TEMPM,DISP=(OLD,PASS)
//LINKMAP EXEC PGM=IEWL,PARM=('LIST,LET,XREF,RMODE(&RMODE)',
// 'AMODE(&AMODE)')
//SYSPRINT DD SYSOUT=&OUTC
//SYSLMOD DD DSN=&MAPLIB(&MAPNAME),DISP=SHR
//SYSUT1 DD UNIT=&WORK,SPACE=(1024,(20,20))
//SYSLIN DD DSN=&&MAP,DISP=(OLD,DELETE)
//* NOLOAD CHANGED TO NOOBJECT
//ASMDSECT EXEC PGM=&ASMBLR,REGION=®,
// PARM='SYSPARM(&A.DSECT),DECK,NOOBJECT'
//SYSPRINT DD SYSOUT=&OUTC
//SYSLIB DD DSN=&INDEX..SDFHMAC,DISP=SHR
// DD DSN=SYS1.MACLIB,DISP=SHR
//SYSUT1 DD UNIT=&WORK,SPACE=(CYL,(5,5))
//SYSUT2 DD UNIT=&WORK,SPACE=(CYL,(5,5))
//SYSUT3 DD UNIT=&WORK,SPACE=(CYL,(5,5))
//SYSPUNCH DD DSN=&DSCTLIB(&MAPNAME),DISP=OLD
//SYSIN DD DSN=&&TEMPM,DISP=(OLD,DELETE)
Como vemos, el procedimiento se divide en 4 pasos:
1º) Paso COPY: aquí únicamente se toma el Mapset de la librería origen (indicada por el usuario) y se copia en un Dataset temporal.
2º) Paso ASMMAP: en este punto se aplica el Ensamblador ASMA90 sobre el mapa origen y se genera el Mapset Físico.
3º) Paso LINKMAP: aquí se ejecuta el Binder sobre el mapset creado en el paso anterior. Se genera, en la librería destino, un objeto ejecutable con el Mapset Físico.
4º) Paso ASMDSECT: en este último paso se genera, a partir del mapa origen, el Mapset Simbólico en la librería destino correspondiente.
Y, con estos 4 pasos, el proceso DFHMAPS crea el Mapset Simbólico y el Mapset Físico asociados a nuestro mapa. Para incluir esta utilidad en nuestra compilación únicamente tendremos que incorporar la ejecución de este procedimiento en nuestro JCL.
Finalmente mencionar que las librerías incluidas en el DFHMAPS podrían variar un poco en vuestro equipo, dependiendo de la instalación del CICS.
Saludos.
El procedimiento estándar DFHMAPS es un proceso que incluye la compilación de nuestros Mapas mediante el Ensamblador ASMA90, así como de todos los pasos necesarios para chequear si nuestro Mapset tiene algún problema en su estructura.
El contenido de DFHMAPS es el siguiente:
//DFHMAPS PROC INDEX='DFH320.CICS',
// MAPLIB='DFH320.CICS.SDFHLOAD',
// DSCTLIB='DFH320.CICS.SDFHMAC',
// MAPNAME=,
// A=,
// AMODE=31,
// RMODE=ANY,
// ASMBLR=ASMA90,
// REG=2048K,
// OUTC=A,
// WORK=SYSDA
//COPY EXEC PGM=IEBGENER
//SYSPRINT DD SYSOUT=&OUTC
//SYSUT2 DD DSN=&&TEMPM,UNIT=&WORK,DISP=(,PASS),
// DCB=(RECFM=FB,LRECL=80,BLKSIZE=400),
// SPACE=(400,(50,50))
//SYSIN DD DUMMY
//* SYSUT1 DD * NEEDED FOR THE MAP SOURCE
//ASMMAP EXEC PGM=&ASMBLR,REGION=®,
//* NOLOAD CHANGED TO NOOBJECT
// PARM='SYSPARM(&A.MAP),DECK,NOOBJECT'
//SYSPRINT DD SYSOUT=&OUTC
//SYSLIB DD DSN=&INDEX..SDFHMAC,DISP=SHR
// DD DSN=SYS1.MACLIB,DISP=SHR
//SYSUT1 DD UNIT=&WORK,SPACE=(CYL,(5,5))
//SYSUT2 DD UNIT=&WORK,SPACE=(CYL,(5,5))
//SYSUT3 DD UNIT=&WORK,SPACE=(CYL,(5,5))
//SYSPUNCH DD DSN=&&MAP,DISP=(,PASS),UNIT=&WORK,
// DCB=(RECFM=FB,LRECL=80,BLKSIZE=400),
// SPACE=(400,(50,50))
//SYSIN DD DSN=&&TEMPM,DISP=(OLD,PASS)
//LINKMAP EXEC PGM=IEWL,PARM=('LIST,LET,XREF,RMODE(&RMODE)',
// 'AMODE(&AMODE)')
//SYSPRINT DD SYSOUT=&OUTC
//SYSLMOD DD DSN=&MAPLIB(&MAPNAME),DISP=SHR
//SYSUT1 DD UNIT=&WORK,SPACE=(1024,(20,20))
//SYSLIN DD DSN=&&MAP,DISP=(OLD,DELETE)
//* NOLOAD CHANGED TO NOOBJECT
//ASMDSECT EXEC PGM=&ASMBLR,REGION=®,
// PARM='SYSPARM(&A.DSECT),DECK,NOOBJECT'
//SYSPRINT DD SYSOUT=&OUTC
//SYSLIB DD DSN=&INDEX..SDFHMAC,DISP=SHR
// DD DSN=SYS1.MACLIB,DISP=SHR
//SYSUT1 DD UNIT=&WORK,SPACE=(CYL,(5,5))
//SYSUT2 DD UNIT=&WORK,SPACE=(CYL,(5,5))
//SYSUT3 DD UNIT=&WORK,SPACE=(CYL,(5,5))
//SYSPUNCH DD DSN=&DSCTLIB(&MAPNAME),DISP=OLD
//SYSIN DD DSN=&&TEMPM,DISP=(OLD,DELETE)
Como vemos, el procedimiento se divide en 4 pasos:
1º) Paso COPY: aquí únicamente se toma el Mapset de la librería origen (indicada por el usuario) y se copia en un Dataset temporal.
2º) Paso ASMMAP: en este punto se aplica el Ensamblador ASMA90 sobre el mapa origen y se genera el Mapset Físico.
3º) Paso LINKMAP: aquí se ejecuta el Binder sobre el mapset creado en el paso anterior. Se genera, en la librería destino, un objeto ejecutable con el Mapset Físico.
4º) Paso ASMDSECT: en este último paso se genera, a partir del mapa origen, el Mapset Simbólico en la librería destino correspondiente.
Y, con estos 4 pasos, el proceso DFHMAPS crea el Mapset Simbólico y el Mapset Físico asociados a nuestro mapa. Para incluir esta utilidad en nuestra compilación únicamente tendremos que incorporar la ejecución de este procedimiento en nuestro JCL.
Finalmente mencionar que las librerías incluidas en el DFHMAPS podrían variar un poco en vuestro equipo, dependiendo de la instalación del CICS.
Saludos.
jueves, 12 de diciembre de 2013
Compilador para Mapas Cobol
Para la compilación de un Mapset (agrupación de Mapas) Cobol no podremos recurrir al compilador estándar de objetos. Esto es debido a que se precisa la intervención de un Ensamblador especial que nada tiene que ver con los procesos empleados para los programas Cobol.
El Ensamblador específico para Mapsets se denomina ASMA90, ubicado en la librería DFH320.CICS.SDFHMAC. Este proceso se encargará de chequear todas las líneas de los Mapas del Mapset y nos informará si hay algún problema en su estructura.
A continuación, mostramos un ejemplo de cómo quedaría el compilador de Mapsets. Recordad que siempre puede haber alguna pequeña variación de una instalación a otra.
//JJCOM9CL JOB (123),'COMPILADOR MAPSET',CLASS=A,MSGCLASS=A,
// MSGLEVEL=(1,1),NOTIFY=&SYSUID
//***************************************************
//* DFHMAPS - PROCEDIMIENTO COMPILACION DE MAPSET
//* MAPSET - AGRUPACION DE MAPAS
//***************************************************
//JOBPROC JCLLIB ORDER=DFH320.CICS.SDFHPROC
//CICSMAP EXEC DFHMAPS2, *COMPILADOR ASMA90
// OUTC=*, *PRINT SYSOUT CLASS
// DSCTLIB=LIBPR.COPYS.JJ00, *DESTINO MAPA SIMBOLICO
// MAPLIB=LIBPR.MODULOS.JJ01, *DESTINO MAPSET FISICO
// MAPNAME=JJ0004M *NOMBRE MAPSET DESTINO
//* UBICACION DEL FUENTE DEL MAPSET
//COPY.SYSUT1 DD DSN=LIBPR.MAPLIB.JJ00(JJ0004M),DISP=SHR
//
//***************************************************
Como vemos, para la implementación de este compilador hemos empleado la invocación al procedimiento estándar DFHMAPS. Dicho procedimiento se encarga de realizar la compilación de nuestro Mapset con el ensamblador ASMA90 y de generar el Mapset Físico asociado.
Para que el funcionamiento sea correcto, a DFHMAPS hay que proporcionarle varios parámetros:
1º) Ubicación del DFHMAPS: que, en nuestro caso, es la librería DFH320.CICS.SDFHPROC. Esto puede variar de una instalación a otra.
//JOBPROC JCLLIB ORDER=DFH320.CICS.SDFHPROC
2º) Parámetro DSCTLIB: se trata de la ubicación en la que se va a almacenar el Mapset Simbólico generado por nuestra compilación. En nuestro ejemplo, hemos puesto la librería LIBPR.COPYS.JJ00.
// DSCTLIB=LIBPR.COPYS.JJ00
3º) Parámetro MAPLIB: es la ubicación en la que deseamos que se almacene el Mapset Físico que se va a generar en nuestra compilación. En el ejemplo, se ha indicado la librería LIBPR.MODULOS.JJ01.
// MAPLIB=LIBPR.MODULOS.JJ01
4º) Parámetro MAPNAME: es el nombre que deseamos que tengan el Mapset Simbólico y el Mapset Físico generados. En el ejemplo hemos elegido JJ0004M.
// MAPNAME=JJ0004M
5º) Ubicación del fuente del Mapset: obviamente, tendremos que indicar la librería en la que se encuentra almacenado el fuente de nuestro Mapset. En el ejemplo, nuestro mapa está en la librería LIBPR.MAPLIB.JJ00.
//COPY.SYSUT1 DD DSN=LIBPR.MAPLIB.JJ00(JJ0004M),DISP=SHR
Mencionar que, si no queremos usar el procedimiento estándar DFHMAPS, lo único que tendríamos que hacer es crearnos nuestro propio JCL e ir incluyendo los pasos que se van ejecutando en aquel procedimiento (pasos COPY, ASMMAP, LINKMAP y ASMDSECT).
Una vez definidos correctamente todos los parámetros precisados, la ejecución de nuestro compilador de Mapas no debería darnos ningún problema.
Saludos.
El Ensamblador específico para Mapsets se denomina ASMA90, ubicado en la librería DFH320.CICS.SDFHMAC. Este proceso se encargará de chequear todas las líneas de los Mapas del Mapset y nos informará si hay algún problema en su estructura.
A continuación, mostramos un ejemplo de cómo quedaría el compilador de Mapsets. Recordad que siempre puede haber alguna pequeña variación de una instalación a otra.
//JJCOM9CL JOB (123),'COMPILADOR MAPSET',CLASS=A,MSGCLASS=A,
// MSGLEVEL=(1,1),NOTIFY=&SYSUID
//***************************************************
//* DFHMAPS - PROCEDIMIENTO COMPILACION DE MAPSET
//* MAPSET - AGRUPACION DE MAPAS
//***************************************************
//JOBPROC JCLLIB ORDER=DFH320.CICS.SDFHPROC
//CICSMAP EXEC DFHMAPS2, *COMPILADOR ASMA90
// OUTC=*, *PRINT SYSOUT CLASS
// DSCTLIB=LIBPR.COPYS.JJ00, *DESTINO MAPA SIMBOLICO
// MAPLIB=LIBPR.MODULOS.JJ01, *DESTINO MAPSET FISICO
// MAPNAME=JJ0004M *NOMBRE MAPSET DESTINO
//* UBICACION DEL FUENTE DEL MAPSET
//COPY.SYSUT1 DD DSN=LIBPR.MAPLIB.JJ00(JJ0004M),DISP=SHR
//
//***************************************************
Como vemos, para la implementación de este compilador hemos empleado la invocación al procedimiento estándar DFHMAPS. Dicho procedimiento se encarga de realizar la compilación de nuestro Mapset con el ensamblador ASMA90 y de generar el Mapset Físico asociado.
Para que el funcionamiento sea correcto, a DFHMAPS hay que proporcionarle varios parámetros:
1º) Ubicación del DFHMAPS: que, en nuestro caso, es la librería DFH320.CICS.SDFHPROC. Esto puede variar de una instalación a otra.
//JOBPROC JCLLIB ORDER=DFH320.CICS.SDFHPROC
2º) Parámetro DSCTLIB: se trata de la ubicación en la que se va a almacenar el Mapset Simbólico generado por nuestra compilación. En nuestro ejemplo, hemos puesto la librería LIBPR.COPYS.JJ00.
// DSCTLIB=LIBPR.COPYS.JJ00
3º) Parámetro MAPLIB: es la ubicación en la que deseamos que se almacene el Mapset Físico que se va a generar en nuestra compilación. En el ejemplo, se ha indicado la librería LIBPR.MODULOS.JJ01.
// MAPLIB=LIBPR.MODULOS.JJ01
4º) Parámetro MAPNAME: es el nombre que deseamos que tengan el Mapset Simbólico y el Mapset Físico generados. En el ejemplo hemos elegido JJ0004M.
// MAPNAME=JJ0004M
5º) Ubicación del fuente del Mapset: obviamente, tendremos que indicar la librería en la que se encuentra almacenado el fuente de nuestro Mapset. En el ejemplo, nuestro mapa está en la librería LIBPR.MAPLIB.JJ00.
//COPY.SYSUT1 DD DSN=LIBPR.MAPLIB.JJ00(JJ0004M),DISP=SHR
Mencionar que, si no queremos usar el procedimiento estándar DFHMAPS, lo único que tendríamos que hacer es crearnos nuestro propio JCL e ir incluyendo los pasos que se van ejecutando en aquel procedimiento (pasos COPY, ASMMAP, LINKMAP y ASMDSECT).
Una vez definidos correctamente todos los parámetros precisados, la ejecución de nuestro compilador de Mapas no debería darnos ningún problema.
Saludos.
miércoles, 11 de diciembre de 2013
Inclusión de librería COPY en el Compilador Cobol
En ocasiones, nuestro programa Cobol llevará alguna sentencia COPY incluida en la sección WORKING-STORAGE. En dichas situaciones, en el compilador tendremos que indicar la ubicación exacta de dicha COPY, identificando la librería que la contiene.
Si incluimos una COPY en nuestro Cobol y lanzamos el Compilador sin más, entonces se generará un mensaje de error informándonos de que no se ha encontrado la librería de copys. Este mensaje, que puede ser un poco confuso, será el siguiente.
The COPY library SYSLIB was not found.
Para informar de la ubicación de la librería de copys a nuestro compilador tendremos que incluir la declaración del parámetro SYSLIB en nuestro JCL. Por ejemplo, si la librería de copys es LIBPR.COPYS.JJ00, entonces la declaración se haría del siguiente modo.
//COBOL.SYSLIB DD DSN=LIBPR.COPYS.JJ00,DISP=SHR
Tengamos en cuenta que el parámetro SYSLIB tendrá que ser especificado en los dos pasos de nuestro compilador (el paso de Compilación y el paso de Linkedition). Sin embargo, la librería de copys únicamente tendrá que ser indicada en el paso de compilación.
Para verlo más claramente, a continuación mostramos cómo quedaría un Compilador ejemplo, una vez incluidas las dos librerías en SYSLIB.
//JJCOM1CL JOB 102,'COMPILADOR COMPLETO',NOTIFY=&SYSUID,
// MSGCLASS=Q,CLASS=A,MSGLEVEL=(1,1),REGION=0M,TIME=(0,7)
//************************************************************** //* SYSLIB ES LA LIB. DE COPYS
//* SYSIN ES LA LIB. DE PROGRAMAS FUENTES
//* SYSLMOD ES LA LIB. DE PROGRAMAS OBJETOS O EJECUTABLES
//************************************************************** //STEP0 EXEC IGYWCLG,PARM.COBOL='LIB,APOST,XREF,MAP,OFFSET'
//* LIBRERIA EN LA QUE SE ENCUENTRA EL COMPILADOR IGYCRCTL
//COBOL.STEPLIB DD DSN=IGY410.SIGYCOMP,DISP=SHR
//* LIBRERIA DE FUENTES Y DE COPYS PARA PASO COBOL
//COBOL.SYSIN DD DSN=LIBPR.FUENTES.JJ00(JJ0004CO),DISP=SHR
//COBOL.SYSLIB DD DSN=LIBPR.COPYS.JJ00,DISP=SHR
//* AÑADIMOS COPYS Y MODULOS PARA PASO LKED DE IGYWCL (PGM HEWL)
//LKED.SYSLIB DD DSN=CEE.SCEELKED,DISP=SHR
//LKED.SYSLMOD DD DSN=LIBPR.MODULOS.JJ01(JJ0004CO),DISP=SHR
//
Como vemos, el compilador se divide en dos partes (paso COBOL y paso LKED), cada una de las cuales tiene su parámetro SYSLIB.
1º) Compilación COBOL: aquí es donde tenemos que especificar, asociado al parámetro SYSLIB, el nombre de la librería donde van a estar almacenadas nuestras copys.
//COBOL.SYSLIB DD DSN=LIBPR.COPYS.JJ00,DISP=SHR
2º) Linkedition LKED: este es el paso de prelinkedit. Aquí también tendremos un parámetro SYSLIB, pero no hace referencia a nuestras copys del programa Cobol.
//LKED.SYSLIB DD DSN=CEE.SCEELKED,DISP=SHR
Hay que tener en cuenta que el compilador mostrado valdría únicamente para programas Cobol que no tengan accesos a DB2. En caso contrario, tendríamos que recurrir a un Compilador más completo, del cual ya hemos hablado en otros post anteriores.
Pues nada, incluyendo la librería de Copys tal y como se indica aquí ya no deberíamos tener problemas a la hora de compilar correctamente nuestros Cobol.
Saludos.
Si incluimos una COPY en nuestro Cobol y lanzamos el Compilador sin más, entonces se generará un mensaje de error informándonos de que no se ha encontrado la librería de copys. Este mensaje, que puede ser un poco confuso, será el siguiente.
The COPY library SYSLIB was not found.
Para informar de la ubicación de la librería de copys a nuestro compilador tendremos que incluir la declaración del parámetro SYSLIB en nuestro JCL. Por ejemplo, si la librería de copys es LIBPR.COPYS.JJ00, entonces la declaración se haría del siguiente modo.
//COBOL.SYSLIB DD DSN=LIBPR.COPYS.JJ00,DISP=SHR
Tengamos en cuenta que el parámetro SYSLIB tendrá que ser especificado en los dos pasos de nuestro compilador (el paso de Compilación y el paso de Linkedition). Sin embargo, la librería de copys únicamente tendrá que ser indicada en el paso de compilación.
Para verlo más claramente, a continuación mostramos cómo quedaría un Compilador ejemplo, una vez incluidas las dos librerías en SYSLIB.
//JJCOM1CL JOB 102,'COMPILADOR COMPLETO',NOTIFY=&SYSUID,
// MSGCLASS=Q,CLASS=A,MSGLEVEL=(1,1),REGION=0M,TIME=(0,7)
//************************************************************** //* SYSLIB ES LA LIB. DE COPYS
//* SYSIN ES LA LIB. DE PROGRAMAS FUENTES
//* SYSLMOD ES LA LIB. DE PROGRAMAS OBJETOS O EJECUTABLES
//************************************************************** //STEP0 EXEC IGYWCLG,PARM.COBOL='LIB,APOST,XREF,MAP,OFFSET'
//* LIBRERIA EN LA QUE SE ENCUENTRA EL COMPILADOR IGYCRCTL
//COBOL.STEPLIB DD DSN=IGY410.SIGYCOMP,DISP=SHR
//* LIBRERIA DE FUENTES Y DE COPYS PARA PASO COBOL
//COBOL.SYSIN DD DSN=LIBPR.FUENTES.JJ00(JJ0004CO),DISP=SHR
//COBOL.SYSLIB DD DSN=LIBPR.COPYS.JJ00,DISP=SHR
//* AÑADIMOS COPYS Y MODULOS PARA PASO LKED DE IGYWCL (PGM HEWL)
//LKED.SYSLIB DD DSN=CEE.SCEELKED,DISP=SHR
//LKED.SYSLMOD DD DSN=LIBPR.MODULOS.JJ01(JJ0004CO),DISP=SHR
//
Como vemos, el compilador se divide en dos partes (paso COBOL y paso LKED), cada una de las cuales tiene su parámetro SYSLIB.
1º) Compilación COBOL: aquí es donde tenemos que especificar, asociado al parámetro SYSLIB, el nombre de la librería donde van a estar almacenadas nuestras copys.
//COBOL.SYSLIB DD DSN=LIBPR.COPYS.JJ00,DISP=SHR
2º) Linkedition LKED: este es el paso de prelinkedit. Aquí también tendremos un parámetro SYSLIB, pero no hace referencia a nuestras copys del programa Cobol.
//LKED.SYSLIB DD DSN=CEE.SCEELKED,DISP=SHR
Hay que tener en cuenta que el compilador mostrado valdría únicamente para programas Cobol que no tengan accesos a DB2. En caso contrario, tendríamos que recurrir a un Compilador más completo, del cual ya hemos hablado en otros post anteriores.
Pues nada, incluyendo la librería de Copys tal y como se indica aquí ya no deberíamos tener problemas a la hora de compilar correctamente nuestros Cobol.
Saludos.
martes, 3 de diciembre de 2013
Simulación del lanzamiento de un Dado en Cobol
Desde siempre sabemos que Cobol no es un lenguaje muy preparado para trabajar con generación de números aleatorios. De hecho, en la mayoría de las aplicaciones en las que se usa Cobol dicha necesidad no existe (ya que se trata de aplicaciones de gestión pura). Sin embargo, si alguna vez necesitamos números aleatorios, existe una forma de generalos.
Para obtener números pseudo-aleatorios tendremos que recurrir a la función RANDOM. Dicha función procede a generar un número aleatorio a partir de un número Semilla dado. Por tanto, obtener un aleatorio será tan simple como invocar a la función RANDOM con un número predefinido.
FUNCTION RANDOM(SEMILLA)
¿Cuál es el problema de la función RANDOM? Bueno, pues tal y como se indica en su definición, lo que hace es generar números pseudo-aleatorios a partir de una semilla. Y el número generado será siempre el mismo para un número semilla dado. Es decir, si no cambiamos la semilla, la invocación a la función RANDOM nos devolverá siempre el mismo número. De ahí que se denominen pseudo-aleatorios.
Entonces, ¿qué podemos hacer para que nunca invoquemos a RANDOM con la misma semilla? ¿cómo podemos ir consiguiendo números semilla siempre distintos de los anteriores? Pues una forma típica de hacerlo es recurrir a la función CURRENT DATE para crearlos.
FUNCTION CURRENT-DATE
Básicamente, lo que haremos es extraer la Fecha y la Hora (que incluirá hasta las centésimas de segundo) del CURRENT DATE actual y usar ese número como semilla para la obtención de un número aleatorio mediante la función RANDOM.
Obsérvese que una semilla extraída así, con Fecha y Hora, nunca podrá ser igual. Es decir, la Fecha-Hora en un momento dado será 20131203121501 y, un segundo después, será 20131203121502, un número distinto. Y si hacemos la consulta dentro de un año, a la misma hora, será 20141203121502, otro número totalmente distinto de los dos anteriores.
Por tanto, la Fecha-Hora nos va a permitir obtener siempre una semilla totalmente distinta de las que nuestro programa ha podido obtener alguna vez en el pasado. Y, por tanto, eso hará que nuestra función RANDOM genere un número aleatorio totalmente nuevo.
Teniendo en cuenta lo anteriormente indicado, podríamos simular un Dado (en este caso, de 100 caras o, lo que es lo mismo, un Simulador de Percentil) en nuestro programa Cobol de la siguiente forma.
*
MOVE FUNCTION CURRENT-DATE TO DATE-TODAY
*
MOVE FECHA-HORA TO SEMILLA
COMPUTE NUM-RANDOM = FUNCTION RANDOM(SEMILLA)
* 10000000000000000
COMPUTE PERCENTIL = NUM-RANDOM / 100000000000000
MOVE PERCENTIL TO PERCENTIL-D
*
Donde las variables estarán definidas del siguiente modo.
*
01 DATE-TODAY.
05 FECHA-HORA PIC 9(16).
05 GUION-D PIC X(1).
05 GMT-H PIC X(2).
05 GMT-M PIC X(2).
*
01 SEMILLA PIC 9(16).
01 NUM-RANDOM PIC 9(16) COMP-3.
*
01 PERCENTIL PIC 999V99.
01 PERCENTIL-D PIC ZZ9,99.
*
Como vemos, lo que hace esta rutina es cargar la fecha actual en DATE-TODAY. A continuación, se mueve la subvariable FECHA-HORA a la SEMILLA de la función RANDOM. Finalmente, se calcula el PERCENTIL a partir del número aleatorio generado.
La ejecución de esta rutina Cobol muestra la siguiente información:
LEIDOS: 000000000000001
CURRENT-DATE: 2013120205182478-0600
FECHA-HORA : 2013120205182478
SEMILLA : 2013120205182478
NUM-RANDOM: 3017732446555855
PERCENTIL : 30,17 %
***
Como vemos, en este ejemplo hemos generado el número aleatorio 30,17. Tal y como lo hemos definido, nuestro "Dado" obtendrá números entre 0 y 100. Sin embargo, la rutina puede ser fácilmente modificada para obtener únicamente números entre 1 y 6, con lo que tendríamos un "verdadero" Dado.
Y eso es todo. Es evidente que, en el mundo Cobol, en la mayoría de las ocasiones la función RANDOM no no será útil, pero siempre es bueno saber que está ahí, por si algún día la necesitamos.
Saludos.
Para obtener números pseudo-aleatorios tendremos que recurrir a la función RANDOM. Dicha función procede a generar un número aleatorio a partir de un número Semilla dado. Por tanto, obtener un aleatorio será tan simple como invocar a la función RANDOM con un número predefinido.
FUNCTION RANDOM(SEMILLA)
¿Cuál es el problema de la función RANDOM? Bueno, pues tal y como se indica en su definición, lo que hace es generar números pseudo-aleatorios a partir de una semilla. Y el número generado será siempre el mismo para un número semilla dado. Es decir, si no cambiamos la semilla, la invocación a la función RANDOM nos devolverá siempre el mismo número. De ahí que se denominen pseudo-aleatorios.
Entonces, ¿qué podemos hacer para que nunca invoquemos a RANDOM con la misma semilla? ¿cómo podemos ir consiguiendo números semilla siempre distintos de los anteriores? Pues una forma típica de hacerlo es recurrir a la función CURRENT DATE para crearlos.
FUNCTION CURRENT-DATE
Básicamente, lo que haremos es extraer la Fecha y la Hora (que incluirá hasta las centésimas de segundo) del CURRENT DATE actual y usar ese número como semilla para la obtención de un número aleatorio mediante la función RANDOM.
Obsérvese que una semilla extraída así, con Fecha y Hora, nunca podrá ser igual. Es decir, la Fecha-Hora en un momento dado será 20131203121501 y, un segundo después, será 20131203121502, un número distinto. Y si hacemos la consulta dentro de un año, a la misma hora, será 20141203121502, otro número totalmente distinto de los dos anteriores.
Por tanto, la Fecha-Hora nos va a permitir obtener siempre una semilla totalmente distinta de las que nuestro programa ha podido obtener alguna vez en el pasado. Y, por tanto, eso hará que nuestra función RANDOM genere un número aleatorio totalmente nuevo.
Teniendo en cuenta lo anteriormente indicado, podríamos simular un Dado (en este caso, de 100 caras o, lo que es lo mismo, un Simulador de Percentil) en nuestro programa Cobol de la siguiente forma.
*
MOVE FUNCTION CURRENT-DATE TO DATE-TODAY
*
MOVE FECHA-HORA TO SEMILLA
COMPUTE NUM-RANDOM = FUNCTION RANDOM(SEMILLA)
* 10000000000000000
COMPUTE PERCENTIL = NUM-RANDOM / 100000000000000
MOVE PERCENTIL TO PERCENTIL-D
*
Donde las variables estarán definidas del siguiente modo.
*
01 DATE-TODAY.
05 FECHA-HORA PIC 9(16).
05 GUION-D PIC X(1).
05 GMT-H PIC X(2).
05 GMT-M PIC X(2).
*
01 SEMILLA PIC 9(16).
01 NUM-RANDOM PIC 9(16) COMP-3.
*
01 PERCENTIL PIC 999V99.
01 PERCENTIL-D PIC ZZ9,99.
*
Como vemos, lo que hace esta rutina es cargar la fecha actual en DATE-TODAY. A continuación, se mueve la subvariable FECHA-HORA a la SEMILLA de la función RANDOM. Finalmente, se calcula el PERCENTIL a partir del número aleatorio generado.
La ejecución de esta rutina Cobol muestra la siguiente información:
LEIDOS: 000000000000001
CURRENT-DATE: 2013120205182478-0600
FECHA-HORA : 2013120205182478
SEMILLA : 2013120205182478
NUM-RANDOM: 3017732446555855
PERCENTIL : 30,17 %
***
Como vemos, en este ejemplo hemos generado el número aleatorio 30,17. Tal y como lo hemos definido, nuestro "Dado" obtendrá números entre 0 y 100. Sin embargo, la rutina puede ser fácilmente modificada para obtener únicamente números entre 1 y 6, con lo que tendríamos un "verdadero" Dado.
Y eso es todo. Es evidente que, en el mundo Cobol, en la mayoría de las ocasiones la función RANDOM no no será útil, pero siempre es bueno saber que está ahí, por si algún día la necesitamos.
Saludos.
viernes, 29 de noviembre de 2013
Creación de un objeto Cobol nuevo
Normalmente, cuando queremos escribir un nuevo programa Cobol, lo que hacemos es realizar una copia de alguno de los ya existentes y desarrollar las modificaciones sobre la misma. Sin embargo, en el ISPF existe la posibilidad de crear un nuevo objeto Cobol desde cero.
La operativa para crear programas Cobol nuevos es muy sencilla. El único problema es que tendremos que teclear todo el código desde el principio, así que tendremos que valorar muy bien si nos merece la pena empezar desde cero o si es preferible modificar la estructura que ya exista en algún otro de nuestros programas.
Los pasos a seguir para crear un nuevo objeto serían los siguientes.
1º) Entramos en el Menú Principal del ISPF.
ISPF Primary Option Menu
2º) Seleccionamos la opción 2 - EDIT - Create or change source data.
2 Edit Create or change source data
3º) En el Panel de entrada tendremos que introducir el nombre de la librería en la que queremos que se almacene nuestro objeto y el nombre que vamos a asignar a nuestro programa Cobol. Por ejemplo, para dar de alta el objeto JJ0004CO en la librería LIBPR.FUENTES.JJ00 pondremos lo siguiente:
ISPF Library:
Project . . . LIBPR
Group . . . . FUENTES
Type . . . . JJ00
Member . . . JJ0004CO
La línea de comandos COMMAND deberá dejarse en blanco para que el ISPF interprete que lo que quiere hacerse es dar de alta un nuevo objeto.
Command ===>
Una vez pulsado INTRO, desaparecerá el panel y pasaremos a una nueva pantalla en la que se nos mostrará el editor del nuevo objeto Cobol creado. Obviamente, el editor estará vacío, ya que dicho objeto aún no tiene ninguna línea dada de alta.
Si en estos momentos no vamos a iniciar la codificación de nuestro programa, entonces bastará con que introduzcamos el comando SAVE en la línea COMMAND.
Command ===> SAVE
Tras pulsar INTRO nos aparecerá el mensaje confirmándonos que el almacenamiento del nuevo objeto se ha llevado a cabo sin problemas. De esta forma, ya tendremos salvado un nuevo objeto Cobol sin ninguna línea de código asignada.
Member JJ0004CO saved
Finalmente, podremos ir a la librería en la que hemos creado el objeto (LIBPR.FUENTES.JJ00 en el ejemplo) y verificar que el programa creado (JJ0004CO) se encuentra realmente en ella.
JJ0004CO 0 2013/11/28 2013/11/28 09:24:51 IBMUSER
Como podemos ver, en nuestro ejemplo el programa se ha creado correctamente, ya que el nuevo objeto aparece, con Size 0, entre los programas JJ0004CB y JJ0005CB.
Y eso sería todo. Como veis, es muy fácil crear un objeto Cobol desde cero. Es ya decisión nuestra empezar la codificación desde el principio o realizar modificaciones sobre la copia de otro programa ya existente.
Saludos.
La operativa para crear programas Cobol nuevos es muy sencilla. El único problema es que tendremos que teclear todo el código desde el principio, así que tendremos que valorar muy bien si nos merece la pena empezar desde cero o si es preferible modificar la estructura que ya exista en algún otro de nuestros programas.
Los pasos a seguir para crear un nuevo objeto serían los siguientes.
1º) Entramos en el Menú Principal del ISPF.
ISPF Primary Option Menu
2º) Seleccionamos la opción 2 - EDIT - Create or change source data.
2 Edit Create or change source data
3º) En el Panel de entrada tendremos que introducir el nombre de la librería en la que queremos que se almacene nuestro objeto y el nombre que vamos a asignar a nuestro programa Cobol. Por ejemplo, para dar de alta el objeto JJ0004CO en la librería LIBPR.FUENTES.JJ00 pondremos lo siguiente:
ISPF Library:
Project . . . LIBPR
Group . . . . FUENTES
Type . . . . JJ00
Member . . . JJ0004CO
La línea de comandos COMMAND deberá dejarse en blanco para que el ISPF interprete que lo que quiere hacerse es dar de alta un nuevo objeto.
Command ===>
Una vez pulsado INTRO, desaparecerá el panel y pasaremos a una nueva pantalla en la que se nos mostrará el editor del nuevo objeto Cobol creado. Obviamente, el editor estará vacío, ya que dicho objeto aún no tiene ninguna línea dada de alta.
Si en estos momentos no vamos a iniciar la codificación de nuestro programa, entonces bastará con que introduzcamos el comando SAVE en la línea COMMAND.
Command ===> SAVE
Tras pulsar INTRO nos aparecerá el mensaje confirmándonos que el almacenamiento del nuevo objeto se ha llevado a cabo sin problemas. De esta forma, ya tendremos salvado un nuevo objeto Cobol sin ninguna línea de código asignada.
Member JJ0004CO saved
Finalmente, podremos ir a la librería en la que hemos creado el objeto (LIBPR.FUENTES.JJ00 en el ejemplo) y verificar que el programa creado (JJ0004CO) se encuentra realmente en ella.
JJ0004CO 0 2013/11/28 2013/11/28 09:24:51 IBMUSER
Como podemos ver, en nuestro ejemplo el programa se ha creado correctamente, ya que el nuevo objeto aparece, con Size 0, entre los programas JJ0004CB y JJ0005CB.
Y eso sería todo. Como veis, es muy fácil crear un objeto Cobol desde cero. Es ya decisión nuestra empezar la codificación desde el principio o realizar modificaciones sobre la copia de otro programa ya existente.
Saludos.
jueves, 28 de noviembre de 2013
Sentencia UPDATE en una tabla DB2
Cuando queramos actualizar la información contenida en un registro de una tabla DB2, la solución será tan fácil como recurrir a la sentencia UPDATE. Este comando nos permitirá actualizar uno o varios de los campos del registro DB2, dejando el resto inalterados.
Para ejecutar el UPDATE sobre el fichero DB2 tendremos que indicar, en primer lugar, el nombre del fichero. A continuación, especificaremos los nombres de los campos que queremos modificar y los valores que deseamos que sustituyan a los que están actualmente contenidos en el registro.
Viéndolo con un ejemplo, la cosa sería así.
*
* MODIFICAMOS REGISTRO EN DB2 JJCLIEM0
* ------------------------------------
EXEC SQL
UPDATE JJCLIEM0
SET ALTURA = :S-ALTURA,
PESO = :S-PESO,
IMC = :S-IMC,
OBSERVACIONES = :S-OBSERVACIONES,
FECHA = CURRENT TIMESTAMP
WHERE CLIENTE = :CLAVE-CLIENTE
END-EXEC
*
Como vemos, la sentencia se divide en varias partes:
1º) Cláusula UPDATE: aquí tenemos que hacer referencia a la tabla DB2 que va a ser actualizada. En el ejemplo, su nombre es JJCLIEM0.
2º) Cláusula SET: aquí debemos especificar todos los campos que van a ser actualizados y, a continuación, los nuevos valores que van a ser almacenados en el registro. Estos valores pueden indicarse como una constante o como una variable (en este último caso, la variable tendrá que estar precedida por el literal ":").
3º) Cláusula WHERE: finalmente, aquí indicaremos el campo clave por el que se va a buscar el registro (o registros, si son varios) que debe ser modificado. En el ejemplo, se actualizarán todos los registros cuyo campo CLIENTE coincida con el valor de la variable CLAVE-CLIENTE.
A continuación, como siempre que accedemos a un fichero DB2, tendremos que proceder a controlar el estado de la variable SQLCODE.
*
* GESTION DEL SQLCODE
* -------------------
EVALUATE TRUE
WHEN SQLCODE = ZEROES
ADD 1 TO CO-LEIDOS-ENTRADA1 DISPLAY 'ACCESO DB2 OK'
WHEN SQLCODE = +100
SET FIN-ENTRADA1 TO TRUE DISPLAY '---> NO EXISTE REGISTRO'
WHEN OTHER
MOVE SQLCODE TO SQLCODE-DIS DISPLAY 'ERROR ACCESO DB2. SQLCODE: ' SQLCODE-DIS
MOVE SQLCODE-DIS TO WS-FILE-ERROR
MOVE 'ERROR ACCESO DB2' TO WS-DESCRIPCION
PERFORM 9980-GENERAR-ERROR
THRU 9980-GENERAR-ERROR-EXIT
END-EVALUATE
*
Este control de SQLCODE nos dirá si el acceso a la tabla DB2 se ha efectuado correctamente, si el registro buscado no existe en la base de datos o si se ha producido algún otro tipo de error. Por supuesto, la ejecución no puede realizar ninguna modificación si no encuentra ningún registro con las características requeridas.
En principio, ejecutando las líneas de código indicadas más arriba no deberíamos tener ningún problema y nuestro programa Cobol tendría que actualizar los registros DB2 sin problema alguno.
Saludos.
Para ejecutar el UPDATE sobre el fichero DB2 tendremos que indicar, en primer lugar, el nombre del fichero. A continuación, especificaremos los nombres de los campos que queremos modificar y los valores que deseamos que sustituyan a los que están actualmente contenidos en el registro.
Viéndolo con un ejemplo, la cosa sería así.
*
* MODIFICAMOS REGISTRO EN DB2 JJCLIEM0
* ------------------------------------
EXEC SQL
UPDATE JJCLIEM0
SET ALTURA = :S-ALTURA,
PESO = :S-PESO,
IMC = :S-IMC,
OBSERVACIONES = :S-OBSERVACIONES,
FECHA = CURRENT TIMESTAMP
WHERE CLIENTE = :CLAVE-CLIENTE
END-EXEC
*
Como vemos, la sentencia se divide en varias partes:
1º) Cláusula UPDATE: aquí tenemos que hacer referencia a la tabla DB2 que va a ser actualizada. En el ejemplo, su nombre es JJCLIEM0.
2º) Cláusula SET: aquí debemos especificar todos los campos que van a ser actualizados y, a continuación, los nuevos valores que van a ser almacenados en el registro. Estos valores pueden indicarse como una constante o como una variable (en este último caso, la variable tendrá que estar precedida por el literal ":").
3º) Cláusula WHERE: finalmente, aquí indicaremos el campo clave por el que se va a buscar el registro (o registros, si son varios) que debe ser modificado. En el ejemplo, se actualizarán todos los registros cuyo campo CLIENTE coincida con el valor de la variable CLAVE-CLIENTE.
A continuación, como siempre que accedemos a un fichero DB2, tendremos que proceder a controlar el estado de la variable SQLCODE.
*
* GESTION DEL SQLCODE
* -------------------
EVALUATE TRUE
WHEN SQLCODE = ZEROES
ADD 1 TO CO-LEIDOS-ENTRADA1 DISPLAY 'ACCESO DB2 OK'
WHEN SQLCODE = +100
SET FIN-ENTRADA1 TO TRUE DISPLAY '---> NO EXISTE REGISTRO'
WHEN OTHER
MOVE SQLCODE TO SQLCODE-DIS DISPLAY 'ERROR ACCESO DB2. SQLCODE: ' SQLCODE-DIS
MOVE SQLCODE-DIS TO WS-FILE-ERROR
MOVE 'ERROR ACCESO DB2' TO WS-DESCRIPCION
PERFORM 9980-GENERAR-ERROR
THRU 9980-GENERAR-ERROR-EXIT
END-EVALUATE
*
Este control de SQLCODE nos dirá si el acceso a la tabla DB2 se ha efectuado correctamente, si el registro buscado no existe en la base de datos o si se ha producido algún otro tipo de error. Por supuesto, la ejecución no puede realizar ninguna modificación si no encuentra ningún registro con las características requeridas.
En principio, ejecutando las líneas de código indicadas más arriba no deberíamos tener ningún problema y nuestro programa Cobol tendría que actualizar los registros DB2 sin problema alguno.
Saludos.
miércoles, 27 de noviembre de 2013
Sentencia DELETE para una tabla DB2
Cuando queramos borrar un registro de un fichero DB2 tendremos que recurrir a la sentencia DELETE. Con ella se conseguirá eliminar el registro completo (si lo que queremos es borrar únicamente algunos de sus campos, entonces esta no es la sentencia que buscamos).
Para la implementación de la sentencia DELETE de una tabla DB2 no tenemos que especificar demasiada información. Bastará con indicar el nombre del dichero DB2 y el nombre del campo clave por el que se debe buscar el registro que queremos eliminar.
El código quedaría del siguiente modo.
*
* BORRAMOS REGISTRO EN DB2 JJCLIEM0
* ---------------------------------
EXEC SQL
DELETE FROM JJCLIEM0
WHERE CLIENTE = :CLAVE-CLIENTE
END-EXEC
La sentencia DELETE se compone de dos partes:
1º) DELETE FROM: en esta cláusula únicamente tendremos que indicar el nombre del fichero DB2 a cuya información queremos acceder.
2º) WHERE: en esta cláusula habrá que incluir un campo clave de la tabla DB2. Esta clave nos servirá para buscar e identificar el registro que debe ser borrado.
A continuación, procederemos a validar el resultado de la variable SQLCODE, para comprobar si la ejecución ha sido correcta o no.
*
* GESTION DEL SQLCODE
* -------------------
EVALUATE TRUE
WHEN SQLCODE = ZEROES
ADD 1 TO CO-LEIDOS-ENTRADA1
DISPLAY 'ACCESO DB2 OK'
WHEN SQLCODE = +100
SET FIN-ENTRADA1 TO TRUE DISPLAY '---> NO EXISTE REGISTRO'
WHEN OTHER
MOVE SQLCODE TO SQLCODE-DIS DISPLAY 'ERROR ACCESO DB2. SQLCODE: ' SQLCODE-DIS
MOVE SQLCODE-DIS TO WS-FILE-ERROR
MOVE 'ERROR ACCESO DB2' TO WS-DESCRIPCION
PERFORM 9980-GENERAR-ERROR
THRU 9980-GENERAR-ERROR-EXIT
END-EVALUATE
La validación del SQLCODE nos deberá decir si todo ha ido correcto, si no existe el registro que se quiere eliminar o si se ha producido algún otro error. Obviamente, si la clave buscada no existe en el DB2, entonces la sentencia no puede eliminar ningún registro de la tabla.
Eso es todo. Tras especificar la información indicada en el post, ya no deberíamos tener ningún problema con la ejecución de la sentencia DELETE en nuestro programa Cobol.
Saludos.
Para la implementación de la sentencia DELETE de una tabla DB2 no tenemos que especificar demasiada información. Bastará con indicar el nombre del dichero DB2 y el nombre del campo clave por el que se debe buscar el registro que queremos eliminar.
El código quedaría del siguiente modo.
*
* BORRAMOS REGISTRO EN DB2 JJCLIEM0
* ---------------------------------
EXEC SQL
DELETE FROM JJCLIEM0
WHERE CLIENTE = :CLAVE-CLIENTE
END-EXEC
La sentencia DELETE se compone de dos partes:
1º) DELETE FROM: en esta cláusula únicamente tendremos que indicar el nombre del fichero DB2 a cuya información queremos acceder.
2º) WHERE: en esta cláusula habrá que incluir un campo clave de la tabla DB2. Esta clave nos servirá para buscar e identificar el registro que debe ser borrado.
A continuación, procederemos a validar el resultado de la variable SQLCODE, para comprobar si la ejecución ha sido correcta o no.
*
* GESTION DEL SQLCODE
* -------------------
EVALUATE TRUE
WHEN SQLCODE = ZEROES
ADD 1 TO CO-LEIDOS-ENTRADA1
DISPLAY 'ACCESO DB2 OK'
WHEN SQLCODE = +100
SET FIN-ENTRADA1 TO TRUE DISPLAY '---> NO EXISTE REGISTRO'
WHEN OTHER
MOVE SQLCODE TO SQLCODE-DIS DISPLAY 'ERROR ACCESO DB2. SQLCODE: ' SQLCODE-DIS
MOVE SQLCODE-DIS TO WS-FILE-ERROR
MOVE 'ERROR ACCESO DB2' TO WS-DESCRIPCION
PERFORM 9980-GENERAR-ERROR
THRU 9980-GENERAR-ERROR-EXIT
END-EVALUATE
La validación del SQLCODE nos deberá decir si todo ha ido correcto, si no existe el registro que se quiere eliminar o si se ha producido algún otro error. Obviamente, si la clave buscada no existe en el DB2, entonces la sentencia no puede eliminar ningún registro de la tabla.
Eso es todo. Tras especificar la información indicada en el post, ya no deberíamos tener ningún problema con la ejecución de la sentencia DELETE en nuestro programa Cobol.
Saludos.
martes, 26 de noviembre de 2013
Sentencia INSERT en una tabla DB2
Cuando queramos almacenar un nuevo registro en un fichero DB2 tendremos que recurrir a la sentencia INSERT. Se trata de un comando SQL que puede ser usado en los programas Cobol como código embebido con las cláusulas EXEC SQL y END-EXEC.
La sentencia INSERT nos permitirá incorporar un nuevo registro en nuestra tabla DB2 mediante la indicación de los campos que queremos que tengan algún contenido. También tendremos que indicar los valores que deberán tener dichos campos.
Un ejemplo de INSERT sería el siguiente.
*
* INSERTAMOS NUEVO REGISTRO EN DB2 JJCLIEM0
* -----------------------------------------
EXEC SQL
INSERT INTO JJCLIEM0
(CLIENTE,
NOMBRE,
APELLIDO1,
APELLIDO2,
ALTURA,
PESO,
IMC,
OBSERVACIONES,
FECHA)
VALUES
(:S-CLIENTE,
:S-NOMBRE,
:S-APELLIDO1,
:S-APELLIDO2,
:S-ALTURA,
:S-PESO,
:S-IMC,
:S-OBSERVACIONES,
CURRENT_TIMESTAMP)
END-EXEC
Como vemos, la sentencia se compone de 2 cláusulas:
1º) Cláusula INSERT INTO: donde tendremos que indicar el nombre del fichero DB2 y la denominación de todos los campos en los que queremos almacenar información para el nuevo registro.
2º) Cláusula VALUES: donde tendremos que especificar los valores que quedarán contenidos en cada uno de los campos especificados anteriormente. Dichos valores podrán proceder de constantes o de variables.
Tras la ejecución de la sentencia INSERT tendremos que establecer, como siempre, un control de la variable SQLCODE. De este modo verificaremos si la inserción se ha realizado correctamente o si, por contra, se ha detectado algún error.
*
* GESTION DEL SQLCODE
* -------------------
EVALUATE TRUE
WHEN SQLCODE = ZEROES
ADD 1 TO CO-LEIDOS-ENTRADA1
DISPLAY 'ACCESO DB2 OK'
WHEN SQLCODE = -803
SET NO-FIN-ENTRADA1 TO TRUE
DISPLAY 'EL REGISTRO YA EXISTE EN LA TABLA'
WHEN OTHER
MOVE SQLCODE TO SQLCODE-DIS
DISPLAY 'ERROR ACCESO DB2. SQLCODE: ' SQLCODE-DIS
MOVE SQLCODE-DIS TO WS-FILE-ERROR
MOVE 'ERROR ACCESO DB2' TO WS-DESCRIPCION
PERFORM 9980-GENERAR-ERROR
THRU 9980-GENERAR-ERROR-EXIT
END-EVALUATE
Una vez controlado el SQLCODE, pasaremos a indicar si la ejecución ha sido correcta, si el registro ya existía en el fichero DB2 o si se ha producido algún otro tipo de error. No debemos olvidar establecer este tipo de controles, ya que es muy frecuente que se obtenga el retorno 803 al intentar dar de alta un registro que ya existe en la tabla.
Y eso es todo. Con estas sencillas indicaciones ya no deberíamos tener problemas a la hora de implementar un INSERT en nuestros programas Cobol.
Saludos.
La sentencia INSERT nos permitirá incorporar un nuevo registro en nuestra tabla DB2 mediante la indicación de los campos que queremos que tengan algún contenido. También tendremos que indicar los valores que deberán tener dichos campos.
Un ejemplo de INSERT sería el siguiente.
*
* INSERTAMOS NUEVO REGISTRO EN DB2 JJCLIEM0
* -----------------------------------------
EXEC SQL
INSERT INTO JJCLIEM0
(CLIENTE,
NOMBRE,
APELLIDO1,
APELLIDO2,
ALTURA,
PESO,
IMC,
OBSERVACIONES,
FECHA)
VALUES
(:S-CLIENTE,
:S-NOMBRE,
:S-APELLIDO1,
:S-APELLIDO2,
:S-ALTURA,
:S-PESO,
:S-IMC,
:S-OBSERVACIONES,
CURRENT_TIMESTAMP)
END-EXEC
Como vemos, la sentencia se compone de 2 cláusulas:
1º) Cláusula INSERT INTO: donde tendremos que indicar el nombre del fichero DB2 y la denominación de todos los campos en los que queremos almacenar información para el nuevo registro.
2º) Cláusula VALUES: donde tendremos que especificar los valores que quedarán contenidos en cada uno de los campos especificados anteriormente. Dichos valores podrán proceder de constantes o de variables.
Tras la ejecución de la sentencia INSERT tendremos que establecer, como siempre, un control de la variable SQLCODE. De este modo verificaremos si la inserción se ha realizado correctamente o si, por contra, se ha detectado algún error.
*
* GESTION DEL SQLCODE
* -------------------
EVALUATE TRUE
WHEN SQLCODE = ZEROES
ADD 1 TO CO-LEIDOS-ENTRADA1
DISPLAY 'ACCESO DB2 OK'
WHEN SQLCODE = -803
SET NO-FIN-ENTRADA1 TO TRUE
DISPLAY 'EL REGISTRO YA EXISTE EN LA TABLA'
WHEN OTHER
MOVE SQLCODE TO SQLCODE-DIS
DISPLAY 'ERROR ACCESO DB2. SQLCODE: ' SQLCODE-DIS
MOVE SQLCODE-DIS TO WS-FILE-ERROR
MOVE 'ERROR ACCESO DB2' TO WS-DESCRIPCION
PERFORM 9980-GENERAR-ERROR
THRU 9980-GENERAR-ERROR-EXIT
END-EVALUATE
Una vez controlado el SQLCODE, pasaremos a indicar si la ejecución ha sido correcta, si el registro ya existía en el fichero DB2 o si se ha producido algún otro tipo de error. No debemos olvidar establecer este tipo de controles, ya que es muy frecuente que se obtenga el retorno 803 al intentar dar de alta un registro que ya existe en la tabla.
Y eso es todo. Con estas sencillas indicaciones ya no deberíamos tener problemas a la hora de implementar un INSERT en nuestros programas Cobol.
Saludos.
jueves, 21 de noviembre de 2013
Paginación de Listado de registros DB2
En ocasiones, cuando queremos extraer un listado de datos de un fichero DB2 y mostrarlos por pantalla, no tenemos la fortuna de que todos los registros DB2 nos quepan en la variable Tabla que hemos creado para recoger la información. En esos casos no nos queda más remedio que recurrir a un proceso de paginación.
Para implementar una paginación necesitaremos una rutina que acceda al fichero DB2 mediante la sentencia FETCH y obtenga registros del mismo hasta que se produzca el llenado de la variable Tabla, momento en el que se incrementará el contador de páginas. A continuación, se mostrá la información por pantalla y se reseteará la variable Tabla. Así podremos volver a proceder a su llenado una vez más, lo que sería algo así como la siguiente página del proceso. Todo esto se repetirá hasta que ya no queden más registros que recuperar del DB2.
La estructura básica sería la siguiente.
*
PERFORM 1000-INICIO
THRU 1000-INICIO-EXIT
*
PERFORM 2000-PROCESO
THRU 2000-PROCESO-EXIT
UNTIL FIN-ENTRADA1
*
La rutina PROCESO, que se ejecutará mientras no se recoja hasta el último registro del fichero DB2 (FIN-ENTRADA), tendría la siguiente forma.
2000-PROCESO.
*
* MOSTRAMOS DATOS POR PANTALLA
* ----------------------------
IF CO-PAG > 0
INITIALIZE CO-TAB
INITIALIZE TAB-SALIDA
SET NO-FIN-PAGINA1 TO TRUE
END-IF
*
* LEEMOS EL SIGUIENTE REGISTRO DEL FICHERO
* ----------------------------------------
PERFORM 9100-LEER-ENTRADA1
THRU 9100-LEER-ENTRADA1-EXIT
UNTIL FIN-PAGINA1
*
PERFORM 3000-LISTADO
THRU 3000-LISTADO-EXIT.
*
2000-PROCESO-EXIT.
EXIT.
*
A continuación, pasamos a detallar los procesos anteriores.
Rutina de Inicio
Aquí tendremos que hacer un primer acceso al fichero DB2 para recuperar el primer registro y almacenarlo en la variable tabla. Si la rutina que hace eso acceso se denomina, por ejemplo, LEER-ENTRADA, entonces la invocación en la rutina de inicio sería la siguiente.
PERFORM 9100-LEER-ENTRADA1
THRU 9100-LEER-ENTRADA1-EXIT.
*
Lectura de Fichero DB2
En la rutina 2000-PROCESO tendremos que incluir la misma invocación a LEER-ENTRADA que se hizo en la rutina Inicio, con la diferencia de que aquí se ejecutará varias veces, hasta que se llegue al final de la página actual (es decir, hasta que se produzca el llenado de la variable Tabla que recoge la información del DB2).
Este subproceso LEER-ENTRADA tendrá que incluir un acceso a la tabla DB2 mediante la sentencia FETCH. La estructura sería algo similar a la siguiente.
9100-LEER-ENTRADA1.
*
* CARGAMOS REGISTRO DE LA TABLA EN LA VARIABLE DE TRABAJO
* -------------------------------------------------------
INITIALIZE PAR-SALIDA
EXEC SQL
FETCH CUR_JJCLIEM0
INTO
:S-CLIENTE,
:S-NOMBRE,
:S-APELLIDO1,
:S-APELLIDO2,
:S-ALTURA,
:S-PESO,
:S-IMC,
:S-OBSERVACIONES INDICATOR :I-OBS,
:S-FECHA
END-EXEC
*
* VERIFICAMOS SI LAS OBSERVACIONES SON NULAS (NULL)
* -------------------------------------------------
IF I-OBS < 0
MOVE '-' TO S-OBSERVACIONES
END-IF
*
* GESTION DEL SQLCODE
* -------------------
EVALUATE TRUE
WHEN SQLCODE = ZEROES
ADD 1 TO CO-TAB
ADD 1 TO CO-LEIDOS-ENTRADA1
WHEN SQLCODE = +100
SET FIN-ENTRADA1 TO TRUE
WHEN OTHER
MOVE SQLCODE TO SQLCODE-DIS
MOVE SQLCODE-DIS TO WS-FILE-ERROR
MOVE 'ERROR ACCESO DB2' TO WS-DESCRIPCION
PERFORM 9980-GENERAR-ERROR
THRU 9980-GENERAR-ERROR-EXIT
END-EVALUATE
*
* CONTROL DE PAGINACION
* ---------------------
IF SQLCODE = 100 OR CO-TAB = 3
SET FIN-PAGINA1 TO TRUE
ADD 1 TO CO-PAG
END-IF
*
* CARGAMOS REGISTRO EN LA TABLA DE DATOS
* --------------------------------------
IF SQLCODE = ZEROS
MOVE S-CLIENTE TO T-CLIENTE(CO-TAB)
MOVE S-NOMBRE TO T-NOMBRE(CO-TAB)
MOVE S-APELLIDO1 TO T-APELLIDO1(CO-TAB)
MOVE S-APELLIDO2 TO T-APELLIDO2(CO-TAB)
MOVE S-ALTURA TO T-ALTURA(CO-TAB)
MOVE S-PESO TO T-PESO(CO-TAB)
MOVE S-IMC TO T-IMC(CO-TAB)
MOVE S-OBSERVACIONES TO T-OBSERVACIONES(CO-TAB)
MOVE S-FECHA TO T-FECHA (CO-TAB)
END-IF.
*
9100-LEER-ENTRADA1-EXIT.
EXIT.
*
Como vemos, la estructura se divide en 4 partes:
1º) Acceso al fichero DB2 mediante FETCH y recogida de los datos en la variable auxiliar correspondiente (incluyendo variables de indicador nulo, si hiciesen falta).
2º) Validación del SQLCODE del acceso al fichero DB2 y actuación en función de su resultado. Hay que observar como, cada vez que el acceso es correcto, se incrementa en 1 unidad el valor del contador de la variable Tabla (CO-TAB).
3º) Control de Paginación. Una vez se ha llenado la variable Tabla, procedemos a incrementar en 1 unidad el contador de páginas y activamos el parámetro de Fin de Página actual. De esta forma, el proceso sabrá que puede pasar a ejecutar la rutina que muestra la información y, posteriormente, repetir el proceso de lectura del fichero DB2 para la siguiente página.
4º) Finalmente, carga de los datos de la variable auxiliar a la posición correspondiente de la variable Tabla, especificada por CO-TAB (esta tabla nos servirá para almacenar todos los registros del fichero DB2).
Rutina de Listado
Por último, tendremos una rutina que irá accediendo a la variable Tabla donde se almacenaron los datos del fichero DB2 e irá mostrando la información por pantalla. El display de registros se ejecutará hasta que se alcance el número máximo de registros almacenados en la variable Tabla (MAX-PAG, que se correspondería con el número de registros visualizables en una página).
3000-LISTADO.
MOVE 1 TO CO-TAB
*
* MOSTRAMOS EL LISTADO DE CLIENTES
* --------------------------------
PERFORM 3100-DISPLAY-REGISTRO
THRU 3100-DISPLAY-REGISTRO-EXIT
UNTIL CO-TAB > MAX-PAG.
*
3000-LISTADO-EXIT.
EXIT.
*
La rutina de Display podrá implementarse de muchas formas. Desde una simple sentencia DISPLAY a una carga de datos sobre un MAPA, o incluso a un volcado de datos sobre un fichero secuencial. Eso ya dependerá del objetivo específico del programa Cobol implementado.
Por ejemplo, con un simple DISPLAY sería así.
3100-DISPLAY-REGISTRO.
*
* MOSTRAMOS LA INFORMACION DEL CLIENTE
* ------------------------------------
DISPLAY CO-TAB ' > '
T-CLIENTE(CO-TAB) ' / '
T-NOMBRE(CO-TAB) ' / '
T-APELLIDO1(CO-TAB) ' / '
T-APELLIDO2(CO-TAB) ' / '
T-ALTURA(CO-TAB) ' / '
T-PESO(CO-TAB) ' / '
T-IMC(CO-TAB) ' / '
T-OBSERVACIONES(CO-TAB) ' / '
T-FECHA(CO-TAB) ' / '
*
ADD 1 TO CO-TAB.
*
3100-DISPLAY-REGISTRO-EXIT.
EXIT.
*
Y nada más. Esto sería suficiente para acceder a un fichero DB2 haciendo uso de un proceso de paginación. Con él se podría obtener un listado de datos a partir de su lectura y mostrar dicha información por pantalla, aunque el número de registros del DB2 supere al número de ocurrencias de la variable Tabla que los recoge.
Saludos.
Para implementar una paginación necesitaremos una rutina que acceda al fichero DB2 mediante la sentencia FETCH y obtenga registros del mismo hasta que se produzca el llenado de la variable Tabla, momento en el que se incrementará el contador de páginas. A continuación, se mostrá la información por pantalla y se reseteará la variable Tabla. Así podremos volver a proceder a su llenado una vez más, lo que sería algo así como la siguiente página del proceso. Todo esto se repetirá hasta que ya no queden más registros que recuperar del DB2.
La estructura básica sería la siguiente.
*
PERFORM 1000-INICIO
THRU 1000-INICIO-EXIT
*
PERFORM 2000-PROCESO
THRU 2000-PROCESO-EXIT
UNTIL FIN-ENTRADA1
*
La rutina PROCESO, que se ejecutará mientras no se recoja hasta el último registro del fichero DB2 (FIN-ENTRADA), tendría la siguiente forma.
2000-PROCESO.
*
* MOSTRAMOS DATOS POR PANTALLA
* ----------------------------
IF CO-PAG > 0
INITIALIZE CO-TAB
INITIALIZE TAB-SALIDA
SET NO-FIN-PAGINA1 TO TRUE
END-IF
*
* LEEMOS EL SIGUIENTE REGISTRO DEL FICHERO
* ----------------------------------------
PERFORM 9100-LEER-ENTRADA1
THRU 9100-LEER-ENTRADA1-EXIT
UNTIL FIN-PAGINA1
*
PERFORM 3000-LISTADO
THRU 3000-LISTADO-EXIT.
*
2000-PROCESO-EXIT.
EXIT.
*
A continuación, pasamos a detallar los procesos anteriores.
Rutina de Inicio
Aquí tendremos que hacer un primer acceso al fichero DB2 para recuperar el primer registro y almacenarlo en la variable tabla. Si la rutina que hace eso acceso se denomina, por ejemplo, LEER-ENTRADA, entonces la invocación en la rutina de inicio sería la siguiente.
PERFORM 9100-LEER-ENTRADA1
THRU 9100-LEER-ENTRADA1-EXIT.
*
Lectura de Fichero DB2
En la rutina 2000-PROCESO tendremos que incluir la misma invocación a LEER-ENTRADA que se hizo en la rutina Inicio, con la diferencia de que aquí se ejecutará varias veces, hasta que se llegue al final de la página actual (es decir, hasta que se produzca el llenado de la variable Tabla que recoge la información del DB2).
Este subproceso LEER-ENTRADA tendrá que incluir un acceso a la tabla DB2 mediante la sentencia FETCH. La estructura sería algo similar a la siguiente.
9100-LEER-ENTRADA1.
*
* CARGAMOS REGISTRO DE LA TABLA EN LA VARIABLE DE TRABAJO
* -------------------------------------------------------
INITIALIZE PAR-SALIDA
EXEC SQL
FETCH CUR_JJCLIEM0
INTO
:S-CLIENTE,
:S-NOMBRE,
:S-APELLIDO1,
:S-APELLIDO2,
:S-ALTURA,
:S-PESO,
:S-IMC,
:S-OBSERVACIONES INDICATOR :I-OBS,
:S-FECHA
END-EXEC
*
* VERIFICAMOS SI LAS OBSERVACIONES SON NULAS (NULL)
* -------------------------------------------------
IF I-OBS < 0
MOVE '-' TO S-OBSERVACIONES
END-IF
*
* GESTION DEL SQLCODE
* -------------------
EVALUATE TRUE
WHEN SQLCODE = ZEROES
ADD 1 TO CO-TAB
ADD 1 TO CO-LEIDOS-ENTRADA1
WHEN SQLCODE = +100
SET FIN-ENTRADA1 TO TRUE
WHEN OTHER
MOVE SQLCODE TO SQLCODE-DIS
MOVE SQLCODE-DIS TO WS-FILE-ERROR
MOVE 'ERROR ACCESO DB2' TO WS-DESCRIPCION
PERFORM 9980-GENERAR-ERROR
THRU 9980-GENERAR-ERROR-EXIT
END-EVALUATE
*
* CONTROL DE PAGINACION
* ---------------------
IF SQLCODE = 100 OR CO-TAB = 3
SET FIN-PAGINA1 TO TRUE
ADD 1 TO CO-PAG
END-IF
*
* CARGAMOS REGISTRO EN LA TABLA DE DATOS
* --------------------------------------
IF SQLCODE = ZEROS
MOVE S-CLIENTE TO T-CLIENTE(CO-TAB)
MOVE S-NOMBRE TO T-NOMBRE(CO-TAB)
MOVE S-APELLIDO1 TO T-APELLIDO1(CO-TAB)
MOVE S-APELLIDO2 TO T-APELLIDO2(CO-TAB)
MOVE S-ALTURA TO T-ALTURA(CO-TAB)
MOVE S-PESO TO T-PESO(CO-TAB)
MOVE S-IMC TO T-IMC(CO-TAB)
MOVE S-OBSERVACIONES TO T-OBSERVACIONES(CO-TAB)
MOVE S-FECHA TO T-FECHA (CO-TAB)
END-IF.
*
9100-LEER-ENTRADA1-EXIT.
EXIT.
*
Como vemos, la estructura se divide en 4 partes:
1º) Acceso al fichero DB2 mediante FETCH y recogida de los datos en la variable auxiliar correspondiente (incluyendo variables de indicador nulo, si hiciesen falta).
2º) Validación del SQLCODE del acceso al fichero DB2 y actuación en función de su resultado. Hay que observar como, cada vez que el acceso es correcto, se incrementa en 1 unidad el valor del contador de la variable Tabla (CO-TAB).
3º) Control de Paginación. Una vez se ha llenado la variable Tabla, procedemos a incrementar en 1 unidad el contador de páginas y activamos el parámetro de Fin de Página actual. De esta forma, el proceso sabrá que puede pasar a ejecutar la rutina que muestra la información y, posteriormente, repetir el proceso de lectura del fichero DB2 para la siguiente página.
4º) Finalmente, carga de los datos de la variable auxiliar a la posición correspondiente de la variable Tabla, especificada por CO-TAB (esta tabla nos servirá para almacenar todos los registros del fichero DB2).
Rutina de Listado
Por último, tendremos una rutina que irá accediendo a la variable Tabla donde se almacenaron los datos del fichero DB2 e irá mostrando la información por pantalla. El display de registros se ejecutará hasta que se alcance el número máximo de registros almacenados en la variable Tabla (MAX-PAG, que se correspondería con el número de registros visualizables en una página).
3000-LISTADO.
MOVE 1 TO CO-TAB
*
* MOSTRAMOS EL LISTADO DE CLIENTES
* --------------------------------
PERFORM 3100-DISPLAY-REGISTRO
THRU 3100-DISPLAY-REGISTRO-EXIT
UNTIL CO-TAB > MAX-PAG.
*
3000-LISTADO-EXIT.
EXIT.
*
La rutina de Display podrá implementarse de muchas formas. Desde una simple sentencia DISPLAY a una carga de datos sobre un MAPA, o incluso a un volcado de datos sobre un fichero secuencial. Eso ya dependerá del objetivo específico del programa Cobol implementado.
Por ejemplo, con un simple DISPLAY sería así.
3100-DISPLAY-REGISTRO.
*
* MOSTRAMOS LA INFORMACION DEL CLIENTE
* ------------------------------------
DISPLAY CO-TAB ' > '
T-CLIENTE(CO-TAB) ' / '
T-NOMBRE(CO-TAB) ' / '
T-APELLIDO1(CO-TAB) ' / '
T-APELLIDO2(CO-TAB) ' / '
T-ALTURA(CO-TAB) ' / '
T-PESO(CO-TAB) ' / '
T-IMC(CO-TAB) ' / '
T-OBSERVACIONES(CO-TAB) ' / '
T-FECHA(CO-TAB) ' / '
*
ADD 1 TO CO-TAB.
*
3100-DISPLAY-REGISTRO-EXIT.
EXIT.
*
Y nada más. Esto sería suficiente para acceder a un fichero DB2 haciendo uso de un proceso de paginación. Con él se podría obtener un listado de datos a partir de su lectura y mostrar dicha información por pantalla, aunque el número de registros del DB2 supere al número de ocurrencias de la variable Tabla que los recoge.
Saludos.
Suscribirse a:
Entradas (Atom)