Desarrollando en Cobol y Natural sobre Plataforma Mainframe

jueves, 31 de julio de 2014

Utilidad IDCAMS para JCL (y 2)

Hace unas semanas comenzamos a ver la forma en que había que implementar la invocación a la utilidad IDCAMS para ejecutar su función de creación de ficheros VSAM indexados (ver post Utilidad IDCAMS para JCL - 1). Hoy trataremos de completar el estudio iniciado en aquel post.




Recordemos que estuvimos viendo parte de las Cards que había que especificar en el paso IDCAMS: SYSPRINT y SYSIN. A continuación, terminaremos de enumerar las declaraciones necesarias para el funcionamiento del DEFINE CLUSTER.

3º) Cláusula DEFINE: Este comando, incluido bajo la SYSIN, le indicará al programa IDCAMS que debe realizar la creación de un fichero VSAM. En este caso, al tratarse de la creación de un fichero indexado KSDS, la cláusula se divide en 3 partes:

- CLUSTER: Donde se indicará el nombre del fichero VSAM. Al tratarse de un fichero KSDS, que tiene asociados un subfichero de índices y un subfichero de datos, los nombres de estos dos últimos deberán ser especificados a continuación.

  DEFINE CLUSTER ( NAME (JJ00.FACTURAS.PEND) -

- DATA: Donde se indicará el nombre del subfichero de datos asociado al fichero VSAM KSDS.

            DATA ( NAME (JJ00.FACTURAS.PEND.DATA) ) -

- INDEX: Donde se indicará el nombre del subfichero de índices asociado al fichero VSAM KSDS.

           INDEX ( NAME (JJ00.FACTURAS.PEND.INDEX) )

Como vemos en el código, la cláusula DEFINE CLUSTER deberá especificar toda la información necesaria para la creación del VSAM. Por tanto, se deberán indicar los valores de los parámetros TRACKS, RECORDSIZE, FREESPACE, VOLUMES, SHAREOPTIONS, KEYS, UNIQUE, IMBED e INDEXED.

                   TRACKS (02 00) -
                   RECORDSIZE (80 80) -
                   FREESPACE (00 00) -
                   VOLUMES (E3WK01) -
                   SHAREOPTIONS (2 3) -
                   KEYS (6 1) -
                   UNIQUE -
                   IMBED ) -


En este caso se emplea el parámetro INDEXED para informar a IDCAMS de que queremos crear un fichero VSAM KSDS (indexado). Pero podríamos haber empleado el parámetro correspondiente a cualquiera de los tipos de ficheros VSAM: NONINDEXED para VSAM ESDS (secuencial), NUMBERED para VSAM RRDS (relativo) o LINEAR para VSAM LDS (lineal).

Una vez especificados todos los parámetros y cards requeridos, procederíamos a lanzar el JCL con la utilidad IDCAMS. Si la ejecución nos da algún problema, tendríamos que revisar el código y asegurarnos de que hemos indicado todos los parámetros necesarios.

En nuestro ejemplo, nosotros procedimos a lanzar el JCL y el job acabó finalizando correctamente. Cuando fuimos a consultar los ficheros existentes en nuestra unidad vimos que habían aparecido estas nuevas entidades.

- Enter "/" to select action             Message      Volume
------------------------------------------------------------- 

 JJ00.FACTURAS.PEND                                   *VSAM*
 JJ00.FACTURAS.PEND.DATA                              ZARES1
 JJ00.FACTURAS.PEND.INDEX                             ZARES1
**************** End of Data Set list ***********************


Como se puede apreciar, el Data Set JJ00.FACTURAS.PEND aparece con la etiqueta *VSAM* en la columna "Volume", lo que lo identifica claramente como un fichero VSAM. Junto a él, podemos observar la presencia de los ficheros DATA e INDEX.

La utilidad IDAMS es ampliamente utilizada hoy en día para la operativa con ficheros VSAM (sí, todavía quedan muchos ficheros VSAM activos en las instalaciones). Pero eso no quita que también podamos utilizarla para nuestra operativa diaria con ficheros secuenciales, ya que admite su tratamiento sin problema alguno.

Pues nada, esperemos que, tras lo comentado hoy sobre esta utilidad, os hayamos resuelto la mayoría de las dudas que podíais tener respecto al empleo de IDCAMS. Como siempre, las preguntas son bienvenidas.

Saludos.

jueves, 24 de julio de 2014

Utilidad IDCAMS para JCL (1)

Para terminar (por el momento) nuestro repaso de las utilidades básicas del mundo JCL, hoy vamos a hablar del programa IDCAMS. Se trata de la utilidad por excelencia cuando hablamos del manejo de ficheros VSAM ya que permite, entre otras cosas, la creación, la eliminación o la carga de información de los mismos.

La utilidad IDCAMS se emplea para realizar la operativa sobre los ficheros VSAM. Lo más importante es que nos permite realizar la creación de los mismos. Aunque también se emplea para realizar la eliminación, la carga de datos o incluso la impresión del contenido de los VSAM.



En realidad, aunque en general se emplea para la operativa con VSAM, IDCAMS puede ser empleado también para operar con ficheros Secuenciales, PDS o ISAM. De hecho, nos permitiría realizar, sin problema alguno, la copia de los registros un fichero Secuencial sobre otro fichero Secuencial.

La función a realizar por el programa IDCAMS deberá ser especificada por uno de los siguientes comandos (que deberán incluirse bajo la card SYSIN):

- DEFINE: El comando DEFINE CLUSTER sirve para indicar que IDCAMS debe proceder a la creación del fichero especificado.

- DELETE: El comando DELETE CLUSTER servirá para eliminar el fichero indicado.

- REPRO: Nos permitirá copiar el contenido de un fichero de entrada a otro fichero de salida.

- PRINT: Procederá a imprimir el contenido del fichero especificado.

A continuación, mostramos un ejemplo de cómo se podría emplear la utilidad IDCAMS en un paso JCL de creación de un fichero VSAM de tipo indexado (KSDS).

//****************************************************
//DEFINE   EXEC PGM=IDCAMS
//SYSPRINT DD   SYSOUT=*
//SYSIN    DD   *
  DEFINE CLUSTER ( NAME (JJ00.FACTURAS.PEND) -
                   TRACKS (02 00) -
                   RECORDSIZE (80 80) -
                   FREESPACE (00 00) -
                   VOLUMES (E3WK01) -
                   SHAREOPTIONS (2 3) -
                   KEYS (6 1) -
                   UNIQUE -
                   IMBED ) -
            DATA ( NAME (JJ00.FACTURAS.PEND.DATA) ) -
           INDEX ( NAME (JJ00.FACTURAS.PEND.INDEX) )
/*

//****************************************************

Como podemos ver, la invocación al programa IDCAMS debe estar acompañada por una serie de declaraciones que son imprescindibles para su correcta ejecución. Son las siguientes:

1º) Card SYSPRINT: Aquí tenemos que indicar el lugar al que deseamos que se envíen todos los mensajes generados durante el proceso de ejecución. Si ponemos SYSOUT=* entonces dicha información se enviará directamente al SPOOL (a la MSGCLASS indicada en nuestro job).

//SYSPRINT DD   SYSOUT=*

2º) Card SYSIN: Son las sentencias de control de entrada para el programa, que deberán ser declaradas justo bajo esta SYSIN. En este caso, el IDCAMS podrá recibir como entrada alguno de los comandos especificados más arriba: DEFINE, DELETE, REPRO o PRINT.

//SYSIN    DD   *

El próximo día continuaremos viendo el resto de las declaraciones que hay que realizar en el paso de nuestro JCL para ejecutar IDCAMS de forma correcta. Aunque parezcan muchos parámetros, hemos de tener en cuenta que, una vez tengamos almacenado nuestro JCL modelo, únicamente tendremos que cambiar el nombre y un par de cosas más para obtener el mismo resultado una y otra vez.

Eso es todo por ahora. Os emplazamos a la segunda parte del post para completar la visión global de la utilidad IDCAMS y, en particular, de su utilización con ficheros VSAM.

Saludos.

jueves, 17 de julio de 2014

Utilidad DFSORT para JCL (y 2)

Hace unas semanas comenzamos a ver la forma en que había que implementar la invocación a la utilidad DFSORT para ejecutar su función SORT asociada (ver post Utilidad DFSORT para JCL - 1). Hoy trataremos de completar el estudio iniciado en aquel post.



Recordemos que estuvimos viendo parte de las Cards que había que especificar en el paso DFSORT: SYSOUT, SORTIN, SORTOUT y SORTWK01. A continuación, terminaremos de enumerar las declaraciones necesarias para el funcionamiento del SORT.

5º) Card SYSIN: Son las sentencias de control que se enviarán en la entrada para el programa. Bajo esta sentencia tendremos que indicar la función que debe ser implementada por la utilidad, cosa que se conseguirá incluyendo el comando correspondiente: por ejemplo, SORT para ordenar, COPY para copiar o MERGE para unir.

//SYSIN DD *    

6º) Comando SORT: Con este comando le estamos indicando al programa DFSORT que realice la ordenación de los registros del fichero secuencial de entrada y deposite el resultado ordenado en el fichero de salida.

  SORT FIELDS=(1,7,CH,A)    

El comando SORT va acompañado de 4 parámetros incluidos en la cláusula FIELDS.

- Parámetro 1: La ordenación se realizará en función del campo clave que comienza en la posición del registro indicada en este parámetro.

- Parámetro 2: Aquí indicamos la longitud del campo clave que se empleará para realizar la ordenación. Recordemos que dicho campo comenzaba en la posición del registro indicada en el parámetro 1.

- Parámetro 3: Especifica el tipo de dato (formato) del campo clave seleccionado.

- Parámetro 4: Indica si la ordenación debe ser ascendente (A) o descendente (D).

En nuestro ejemplo, la ordenación del fichero JJ00.FACTURAS.UNSORTED.DATA se realizará de forma ascendente (A) y analizando el contenido, en formato carácter (CH), del campo que comienza en la posicion 1 y acaba en la posición 7 (longitud 7).

Una vez provisionadas todas las cards indicadas, podremos submitir el JCL que incluya este proceso de ordenación. Si seguimos las instrucciones al pie de la letra, el job no debería darnos ningún error. En nuestro ejemplo, el lanzamiento del JCL acabó con la generación del nuevo fichero JJ00.FACTURAS.SORTED.DATA, donde aparecieron los mismos registros que en el fichero original, pero ordenados en función del campo incluido entre las posiciones 1 y 7.

Comentar que esta función de ordenación mediante el programa DFSORT (o ICEMAN) es muy utilizada en la mayoría de las instalaciones actuales. Es practicamente imposible encontrar, hoy en día, una aplicación cuyos JCL no utilicen comandos SORTS para realizar la ordenación de sus ficheros secuenciales de datos.

Pues nada, eso es todo lo que queríamos comentaros sobre la utilidad DFSORT y, en particular, sobre su comando SORT. Ya sabéis que podéis preguntarnos cualquier duda que os surja al respecto.

Saludos.

miércoles, 16 de julio de 2014

Error al definir una Variable Host entre OPEN y FETCH

Se trata de un problema típico que suele aparecer cuando los programadores novatos intentan hacer sus primeros programas Cobol con tratamiento de tablas DB2. Normalmente es debido a que aún continúan pensando que trabajan con su lenguaje de programación anterior, en el que no se precisaba ningún tratamiento de cursores asociados a las tablas de la base de datos.

Cuando se une lo anteriormente comentado con el empleo de variables Fecha, es muy común que en la ejecución del programa aparezca el SQLCODE -180. Entonces el programador se vuelve loco tratando de identificar qué es lo que ha definido mal a la hora de invocar al SQL.

El error SQLCODE -180 está asociado al siguiente mensaje: "THE DATE, TIME OR TIMESTAMP VALUE value IS INVALID". Significa que estamos intentando hacer un acceso a un campo de tipo Hora o Fecha de la tabla DB2 con un dato con formato incorrecto.



Aquí tenemos un ejemplo de código que daría el error SQLCODE -180 mencionado.

 DATA DIVISON.
 WORKING-STORAGE SECTION.
***********************************************
* INTERFAZ DB2                                
***********************************************

         EXEC SQL         
           INCLUDE FACTURAS
         END-EXEC. 

*        
         EXEC SQL DECLARE FACTURAS-C CURSOR FOR
           SELECT *                           
           FROM   FACTURAS                    
           WHERE  FINACTIV < :WFIN         
           ORDER BY NUMERNIF                  
         END-EXEC.                              

.
.
.
 PROCEDURE DIVISION.
*                              
*    ABRIMOS FICHEROS Y CURSORES
*    ---------------------------
         EXEC SQL              
           OPEN FACTURAS-C     
         END-EXEC.      

.
.
.    
     MOVE FECHA-ACTIV-F   TO WFIN
                     
*                                                  
*    LEEMOS REGISTRO DEL FICHERO DE DATOS (FACTURAS)
*    --------------------------------------        
         EXEC SQL                                  
           FETCH FACTURAS-C                        
             INTO                                  
                  :NUMERNIF,                       
                  :FINACTIV,

                  :CSITCUEN       
         END-EXEC                   

        
Como podemos observar, el código anterior se divide en 3 partes.

1º) En la primera se define el cursor FACTURAS-C de la tabla DB2 FACTURAS, que precisará recibir como parámetro de entrada la variable WFIN (fecha de actividad).

2º) En la segunda se realiza la apertura del cursor FACTURAS-C mediante el comando OPEN.

3º) En la tercera se carga el valor de la variable WFIN, y se realiza una invocación al cursor FACTURAS-C mediante el comando FETCH. Esta acción recuperará información de la tabla FACTURAS en función de la fecha provisionada en el parámetro WFIN.

Pues bien, al ejecutar el código anterior nuestro programa nos devolverá un error SQLCODE -180 al intentar hacer el OPEN del cursor FACTURAS-C. Aunque este error hace referencia a que la fecha FINACTIV especificada tiene un formato incorrecto, curiosamente el problema no tiene nada que ver con la fecha que hemos provisionado en la variable WFIN.



En realidad, el error se produce debido a que hemos especificado el valor del parámetro WFIN entre el OPEN del cursor y la sentencia FETCH. Por tanto, cuando el SQL va a realizar el OPEN de FACTURAS-C se encuentra con que el parámetro host WFIN aún no tiene ninguna fecha provisionada y devuelve un SQLCODE -180, queriendo indicar con ello que no tiene formato fecha.

Por tanto, lo correcto en estos casos es indicar el valor de las variables host empleadas en el cursor antes de realizar el OPEN del mismo. La sentencia FETCH lo único que hace es recuperar el siguiente registro del DB2 en función de la extracción propuesta en la apertura del cursor, así que no tiene sentido que definamos las variables después de hacer la invocación al OPEN..

Haciendo dicho cambio, la PROCEDURE DIVISION del ejemplo anterior quedaría del siguiente modo:

 PROCEDURE DIVISION.
     MOVE FECHA-ACTIV-F   TO WFIN     
*                              
*    ABRIMOS FICHEROS Y CURSORES
*    ---------------------------
         EXEC SQL              
           OPEN FACTURAS-C     
         END-EXEC.      

.
.
.                       
*                                                  
*    LEEMOS REGISTRO DEL FICHERO DE DATOS (FACTURAS)
*    --------------------------------------        
         EXEC SQL                                  
           FETCH FACTURAS-C                        
             INTO                                  
                  :NUMERNIF,                       
                  :FINACTIV,

                  :CSITCUEN       
         END-EXEC 


Obviamente, no se trata de un error que se observe entre los programadores experimentados pero, sin embargo, hemos visto a muchos principiantes cometerlo. Normalmente, se trata de personas que previamente han trabajado con otros lenguajes en los que no era necesario hacer un OPEN previo a la lectura del fichero de base de datos. Por tanto, caen en el error de provisionar los parámetros del cursor justo antes del FETCH, creyendo que este último comando va a funcionar del mismo modo que el READ de otros lenguajes. Pero bueno, una vez que se encuentran con este problema, aprenden rápidamente la lección y la cosa no vuelve a repetirse.

La "ventaja" de este error es que, al estar trabajando con OPEN y FETCH, no vamos a producir ningún daño irreparable con la ejecución de nuestro programa. Lo único que tendremos que hacer es corregir el código y volver a compilar y linkeditar el objeto.

Si a vosotros os pasa esto mismo alguna vez, al menos esperamos que este post os sirva de ayuda para solucionar el problema con rapidez y perder el menor tiempo posible. Con eso nos damos por satisfechos.

Saludos.

jueves, 10 de julio de 2014

Utilidad DFSORT para JCL (1)

En múltiples ocasiones, trabajando con información asociada a nuestra aplicación, hemos tenido la necesidad de ordenar los datos que aparecen en un determinado fichero secuencial. En ZOS tenemos la posibilidad de realizar dicha acción y almacenar los registros ordenados en un nuevo fichero.

La utilidad DFSORT (también denominada ICEMAN) se emplea para realizar la ordenación de los registros del fichero secuencial indicado y almacenar el resultado ordenado en un nuevo fichero. Aparte de esto, la utilidad también puede ser empleada para realizar simples copias de ficheros o para unir el contenido de varios ficheros.



Para ejecutar las funciones anteriores tendremos que hacer uso de alguno de los siguientes comandos asociados al programa DFSORT.

- SORT: ordenación de registros de un fichero.
- COPY: realizar copia de un fichero.
- MERGE: unir el contenido de varios ficheros.

A continuación, mostramos cómo debería usarse la utilidad DFSORT en un JCL con el que pretende realizarse la ordenación de los datos de un fichero. Para ello, deberá hacerse uso del comando SORT.

//*******************************************************

//*   DES: ORDENACION DE REGISTROS DE UN FICHERO        
//*******************************************************
//PASO1    EXEC PGM=DFSORT                              
//SYSOUT   DD SYSOUT=*                                  
//SORTIN   DD DSN=JJ00.FACTURAS.UNSORTED.DATA,DISP=OLD   
//SORTOUT  DD DSN=JJ00.FACTURAS.SORTED.DATA,             
//            DISP=(NEW,CATLG,DELETE),UNIT=SYSDA,       
//            SPACE=(CYL,(1,1)),                        
//            LRECL=80,RECFM=F,BLKSIZE=0                
//SORTWK01 DD SPACE=(CYL,(1,1)),UNIT=SYSDA              
//SYSIN DD *                                            
  SORT FIELDS=(1,7,CH,A)              
          

Las declaraciones que hay que realizar en el paso del JCL son las siguientes:

1º) Card SYSOUT: Aquí tenemos que indicar el lugar al que deseamos que se envíen todos los mensajes generados durante el proceso de ejecución. Si ponemos SYSOUT=* entonces dicha información se enviará directamente al SPOOL (a la MSGCLASS indicada en nuestro job).

//SYSOUT   DD SYSOUT=*           

2º) Card SORTIN: Aquí se debe introducir el nombre del fichero secuencial de entrada cuyos registros deseamos que sean ordenados. En nuestro ejemplo se indica el fichero JJ00.FACTURAS.UNSORTED.DATA.

//SORTIN   DD DSN=JJ00.FACTURAS.UNSORTED.DATA,DISP=OLD   

3º) Card SORTOUT: Del mismo modo, aquí debe indicarse el nombre del nuevo fichero de salida en el que se van a almacenar los registros ordenados. En el ejemplo nosotros queremos que la información ordenada se guarde en el fichero JJ00.FACTURAS.SORTED.DATA, que será creado con los datos especificados.

//SORTOUT  DD DSN=JJ00.FACTURAS.SORTED.DATA,             
//            DISP=(NEW,CATLG,DELETE),UNIT=SYSDA,       
//            SPACE=(CYL,(1,1)),                        
//            LRECL=80,RECFM=F,BLKSIZE=0  


4º) Card SORTWK01: Aquí se indica el tamaño del fichero auxiliar de trabajo que se va a emplear mientras se realizan los procesos de ordenación. Si el volumen de datos fuera muy elevado y no bastara con un único fichero auxiliar, se pueden añadir declaraciones con data sets adicionales: SORTWK02, SORTWK03, SORTWK04, etc...

//SORTWK01 DD SPACE=(CYL,(1,1)),UNIT=SYSDA       

El próximo día continuaremos viendo el resto de las declaraciones que hay que realizar en el paso de nuestro JCL para ejecutar un SORT de forma correcta. Aunque parezcan muchos parámetros, en realidad esto sólo nos parecerá difícil la primera vez. Después, simplemente habrá que repetir el mismo procedimiento para obtener resultados similares.

Eso es todo por ahora. Os emplazamos a la segunda parte del post para completar la visión global de la utilidad DFSORT y, en particular, de su función SORT.

Saludos.

jueves, 3 de julio de 2014

Descargar Fichero Secuencial al PC

Cuando estemos trabajando en nuestra aplicación, en ocasiones nos surgirá la necesidad de descargar al PC alguno de los Ficheros Secuenciales que estamos usando para almacenar datos. Esta acción se puede efectuar desde ISPF sin necesidad de recurrir a herramientas externas adicionales.

La operación de Descarga de Fichero Secuencial a PC puede realizarse desde la opción Command del ISPF. Para ello, únicamente tendremos que indicarle el nombre completo del Data Set en ZOS y el nuevo nombre con el que queremos que se almacene la información en nuestro PC.

Entrando más en detalle, estos serían los pasos que habría que seguir para descargarnos la información de un PS a cualquiera de los directorios de nuestro PC.

1º) Opción Command. Desde el menú POM del ISPF, seleccionamos la opción 6 - Command.

6  Command       Enter TSO or Workstation commands

2º) Recibir archivos del sistema principal. Desde el panel Command, se va al menú "Acciones" y se selecciona la opción "Recibir archivos del sistema principal".



3º) En la Ventana de Recepcion de archivos del sistema principal, hay que introducir la siguiente información:

- Sistema principal. Nombre del archivo: Se trata del nombre del Fichero Secuencial. Por ejemplo, introducimos el nombre de Data Set: 'JJ00.FACTURAS.LISTADO' (como vemos, el nombre del fichero debe teclearse entre comillas).

- PC. Nombre del archivo: Se indica el nombre con el que se debe almacenar en nuestro PC. También hay que especificar el directorio correspondiente. Por ejemplo, indicamos: c:\documents and settings\jose javier\mis documentos\a documentos\informatica\Listado.

- Tipo de Transferencia: Se debe seleccionar la opción "Text".

Finalmente, una vez introducidos los datos, pulsamos el botón "Añadir a la lista".



4º) A continuación, nos aparecerán los valores introducidos (Nombre de archivo del sistema, Nombre de archivo de Pc, Tipo) en la Lista de Transferencia. Si todo está correcto, seleccionamos el fichero a transferir y pulsamos el botón "Recibir".



5º) Finalmente, nos aparecerá una ventana informándonos del Estado de recepción del archivo (esto es, de la evolución del proceso de descarga del Fichero Secuencial al PC). Los datos mostrados son el Archivo del sistema principal actual, los Bytes totales transferidos y el Tiempo transcurrido.



Una vez terminada la descarga, desaparecerá la ventana y volveremos al Panel Command del ISPF. Si todo ha ido bien, en nuestro PC ya debería aparecer el archivo con formato txt. Si no aparece con la extensión txt podemos añadírsela nosotros mismos, ya que se trata de un fichero de texto que podrá ser abierto, sin problema alguno, por cualquier procesador de textos.

Como vemos, aquí tenemos una forma muy simple de transferirnos nuestros ficheros secuenciales al PC sin necesidad de recurrir a herramientas adicionales. Siguiendo los pasos indicados, es muy difícil que nos encontremos con errores en el proceso.

Y eso es todo hoy. Esperamos que la funcionalidad explicada os sea de utilidad. Nosotros la hemos usado en repetidas ocasiones en nuestra aplicación y nos ha servido para ahorrar bastante tiempo y trabajo.

Saludos.

Related Posts Plugin for WordPress, Blogger...