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.
Desarrollando en Cobol y Natural sobre Plataforma Mainframe
jueves, 31 de julio de 2014
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.
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.
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.
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.
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.
viernes, 4 de julio de 2014
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.
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.
Suscribirse a:
Entradas (Atom)