Mostrando entradas con la etiqueta write. Mostrar todas las entradas
Mostrando entradas con la etiqueta write. Mostrar todas las entradas

viernes, 2 de marzo de 2012

COBOL/CICS vol.2: acceso a ficheros.

En este artículo veremos un programa CICS que recoge información de la pantalla y actualiza un fichero VSAM. Al igual que en el ejemplo anterior, se trata de un programa conversacional, es decir, el código se ejecutará de principio a fin sin devolver el control al CICS en ningún momento (salvo al finalizar la ejecución).

En el artículo COBOL/CICS vol.1: primer contacto vimos como crear una transacción CICS y asociarla a nuestro programa, por lo que no volveremos a explicarlo.
En esta ocasión veremos como definir un fichero VSAM en CICS para que pueda ser utilizado por nuestro programa. El sistema será el mismo que para definir un programa.

Utilizaremos la transacción CEDA para definir el fichero.
Escribiremos CEDA DEFINE FILE
La información a rellenar será:
File
Group
DSNAme
Add = yes
BRowse = yes
DELete = yes
READ = yes
UPDATE = yes

Una vez definido, tendremos que instalarlo:
CEDA INSTALL FILE(FILE1)
Se debe rellenar el campo Group


Ahora si consultamos la transacción CEMT veremos que ya aparece nuestro fichero:
CEMT I FILE(FILE1)


Ya tenemos el fichero listo para usar.

Antes de meternos a ver el programa, vamos a ver las instrucciones CICS de acceso a fichero que vamos a utilizar.

STARTBR: Apertura del fichero

      EXEC CICS STARTBR
                FILE ('FILE1')
                RIDFLD (WX-CODIGO)
                KEYLENGTH (WX-LONG-CLAVE)
                GTEQ
                RESP (WX-RESP)
      END-EXEC.


Donde:
FILE1 es el nombre que le hemos dado a nuestro fichero en CICS.
RIDFLD es el campo clave del fichero.
KEYLENGTH es la longitud de la clave.
GTEQ indica mayor o igual.
RESP indicamos la variable donde guardaremos el código de respuesta.

DELETE: borra un registro del fichero

    EXEC CICS DELETE
              RIDFLD (WX-CODIGO)
              FILE ('FILE1')
              NOHANDLE
    END-EXEC.


Nota: si usamos NOHANDLE el código de respuesta lo tendremos en EIBRESP


WRITE: graba un registro

     EXEC CICS WRITE
               FILE ('FILE1')
               RIDFLD (WX-CODIGO)
               LENGTH (WX-LONG-REG)
               FROM (REG-VSAMKSDS)
               NOHANDLE
     END-EXEC.

Donde:
LENGTH es la longitud del registro
FROM es el nivel 01 que define la estructura del fichero

READ: lectura directa

     EXEC CICS READ
               RIDFLD (WX-CODIGO)
               FILE ('FILE1')
               INTO (REG-VSAMKSDS)
               LENGTH (WX-LONG-REG)
               NOHANDLE
     END-EXEC.


Donde:
INTO es el nivel 01 que define la estructura del fichero.

READNEXT: lectura del fichero

     EXEC CICS READNEXT
               INTO (REG-VSAMKSDS)
               RIDFLD (WX-CODIGO)
               FILE ('FILE1')
               KEYLENGTH (WX-LONG-CLAVE)
               RESP (WX-RESP)
     END-EXEC.



UPDATE: indica lectura con intención de actualizar

     EXEC CICS READ
               RIDFLD (WX-CODIGO)
               FILE ('FILE1')
               INTO (REG-VSAMKSDS)
               LENGTH (WX-LONG-REG)
               UPDATE
               NOHANDLE
     END-EXEC.


Nota: con UPDATE bloqueamos el registro para que no se pueda acceder a él mientras tanto

REWRITE: actualiza un registro

     EXEC CICS REWRITE
               FILE ('FILE1')
               LENGTH (WX-LONG-REG)
               FROM (REG-VSAMKSDS)
               NOHANDLE
     END-EXEC.


ENDBR: cierre del fichero

     EXEC CICS ENDBR
               FILE ('FILE1')
               RESP (WX-RESP)
     END-EXEC.



La semana que viene continuaremos el artículo con el código completo del programa y su ejecución. Esta no hay tiempo para más!

miércoles, 23 de febrero de 2011

Natural/ADABAS para coboleros: parte I.

¿Qué es Natural? Es un lenguaje de programación de la empresa Software AG que también se utiliza en entornos mainframe. La base de datos que lo acompaña es ADABAS. Del mismo modo que Natural podría tener similitudes con COBOL, ADABAS no las tiene en absoluto con DB2.
Hoy día no tengo conocimiento de que quede algún banco en España que lo utilice, pues el único que conocí de primera mano lo estaba migrando a COBOL. Creo que telefónica todavía tenía una parte en Natural/ADABAS...

En este artículo nos haremos una idea de cómo codificar en Natural asociándolo a un programa COBOL. Tomaremos como ejemplo el "Ejemplo 1" del manual de COBOL para principiantes.

Vamos a construir un programa que recogerá datos de la SYSIN de un JCL, y displayará la inforamción contenida en él.

JCL:

//**************EJECUCION NATURAL*******************
//**************************************************
//PROG1 EXEC NATBAT
//CMPRINT DD SYSOUT=*
//CMSYNIN DD *
LOGON SYSEXBAT
EXECUTE PGMNAT1
FIN
//SYSIN DD *
JOSE LOPEZ VAZQUEZ %
HUGO CASILLAS DIAZ %
JAVIER CARBONERO %
PACO GONZALEZ
/*


Donde EXEC NATBAT indica que vamos a ejecutar un programa natural en modo batch(puede cambiar según instalación).
CMPRINT DD SYSOUT=* indica que la información "displayada" se quedará en la cola CMPRINT (no lo vamos a guardar en un fichero).
En CMSYNIN DD * hace logon a la librería e indicamos el programa q vamos a ejecutar (PGMNAT1).
En SYSIN incluimos la información que va a recibir el programa. El '%' indica que la información continúa en la siguiente línea.


Programa:

DEFINE DATA LOCAL
 1 WI-INDICE(P4)
 1 #WX-NOMBRE1(A20)
 1 #WX-NOMBRE2(A20)
 1 #WX-NOMBRE3(A20)
 1 #WX-NOMBRE4(A20)
 1 WX-TABLA-NOMBRES
   2 WX-NOMBRE(A20/4)
END-DEFINE

INPUT #WX-NOMBRE1 #WX-NOMBRE2 #WX-NOMBRE3 #WX-NOMBRE4

MOVE #WX-NOMBRE1 TO WX-NOMBRE(1)
MOVE #WX-NOMBRE2 TO WX-NOMBRE(2)
MOVE #WX-NOMBRE3 TO WX-NOMBRE(3)
MOVE #WX-NOMBRE4 TO WX-NOMBRE(4)

FOR WI-INDICE = 1 TO 4
   WRITE 'WX-NOMBRE:'WX-NOMBRE(WI-INDICE)

END


Donde el área "DEFINE DATA LOCAL" equivaldría a nuestra WORKING-STORAGE; ahí definiríamos las variables/copys que necesitásemos para el programa. En nuestro caso:

WI-INDICE: empaquetado(P) de 4 posiciones. Equivaldría a un 9(4) COMP-3. Los índices para bucles en natural deben ser siempre numéricos (N) o empaquetados (P).
#WX-NOMBRE1: alfanumérico (A) de 20. Equivaldría a nuestro PIC X(20). La almohadilla indica que es una variable que se recibe por INPUT.
WX-TABLA-NOMBRES: sería una tabla interna donde el campo WX-NOMBRE es un alfanumérico (A) de 20 y se repite 4 veces. Equivaldría a nuestro OCCURS 4 TIMES.

A continuación codificaríamos el "PROCESO" del programa. En nuestro caso:

INPUT: recoge los datos introducidos por SYSIN.
MOVE/TO: para informar variables existen otras opciones:
WX-NOMBRE(1) := #WX-NOMBRE1 ó
ASSIGN WX-NOMBRE(1) = #WX-NOMBRE1

FOR: es uno de los bucles de natural. Las sentencias se repetirán "PARA" WI-INDICE = 1, =2, =3 e =4.
WRITE: escribe en el CMPRINT, que equivaldría a nuestra SYSOUT. La sentencia WRITE equivaldría a nuestro DISPLAY. En natural también existe la sentencia DISPLAY. La diferencia con el WRITE está en que el DISPLAY da formato a los datos, crea columnas con cabeceras por ejemplo.

El resultado usando WRITE sería:

WX-NOMBRE: JOSE LOPEZ VAZQUEZ
WX-NOMBRE: HUGO CASILLAS DIAZ
WX-NOMBRE: JAVIER CARBONERO
WX-NOMBRE: PACO GONZALEZ


Y usando DISPLAY sería:

      WX-NOMBRE:
--------------------

JOSE LOPEZ VAZQUEZ
HUGO CASILLAS DIAZ
JAVIER CARBONERO
PACO GONZALEZ


Esto es un ejemplo muuuy sencillo, lo he probado con la versión de demo que se puede descargar desde la página de Software AG. Eso sí, sólo el código que los JCLs no se puede.
Para la próxima veremos el ejemplo de acceso a ADABAS más sencillo, y así tener una idea de como funciona esta base de datos : )

lunes, 21 de febrero de 2011

Ejemplo 2: leer de SYSIN y escribir en fichero.

En este ejemplo vamos a ejecutar un programa SIN DB2, que recoge información de la SYSIN del JCL del mismo modo que vimos en el ejemplo 1. La diferencia estará en que en esta ocasión vamos a escribir la información en un fichero en lugar de en la SYSOUT.

JCL:

//******************************************************
//**************************** BORRADO *****************
//BORRADO EXEC PGM=IDCAMS
//SYSPRINT DD SYSOUT=*
//SYSIN DD *
DEL FICHERO.CON.NOMBRES
SET MAXCC = 0
//******************************************************
//*********** EJECUCION DEL PROGRAMA PRUEBA2 ***********
//PROG1 EXEC PGM=PRUEBA2
//SYSOUT  DD SYSOUT=*
//FICHERO DD DSN=FICHERO.CON.NOMBRES,
//           DISP=(NEW, CATLG, DELETE),

//           SPACE=(TRK,(50,10))
//SYSIN DD *
JOSE LOPEZ VAZQUEZ HUGO CASILLAS DIAZ JAVIER CARBONERO PACO GONZALEZ
/*


En este ejemplo añadimos un nuevo paso, el IDCAMS. Este programa sirve para borrar ficheros que se crean a lo largo del JCL. En nuestro caso borrará el fichero que se va a crear en el programa. Así podremos ejecutarlo tantas veces como queramos sin generar el mismo fichero una y otra vez.
El paso de ejecución del programa PRUEBA2 es similar al del ejemplo 1, sólo le hemos añadido la definición del fichero de salida "FICHERO".

PROGRAMA:

 IDENTIFICATION DIVISION.
 PROGRAM-ID. PRUEBA2.
*==========================================================*
*     PROGRAMA QUE LEE DE SYSIN Y ESCRIBE EN FICHERO
*==========================================================*
*
 ENVIRONMENT DIVISION.
*
 CONFIGURATION SECTION.
*
 SPECIAL-NAMES.
     DECIMAL-POINT IS COMMA.
*
 INPUT-OUTPUT SECTION.
*
 FILE-CONTROL.
*
 SELECT FICHERO ASSIGN TO FICHERO
                STATUS IS FS-FICHERO.
*
 DATA DIVISION.
*
 FILE SECTION.
*
* Fichero de salida de longitud fija (F) igual a 20.
 FD FICHERO RECORDING MODE IS F
            BLOCK CONTAINS 0 RECORDS
            RECORD CONTAINS 20 CHARACTERS.
 01 REG-FICHERO PIC X(20).
*
 WORKING-STORAGE SECTION.
* FILE STATUS
 01 FS-STATUS.
    05 FS-FICHERO        PIC X(2).
       88 FS-FICHERO-OK          VALUE '00'.
*
* VARIABLES
 01 WI-INDICE            PIC 9(4) COMP.
 01 WX-SYSIN             PIC X(80).
 01 WX-TABLA-NOMBRES.
    05 WX-NOMBRE         PIC X(20) OCCURS 4 TIMES.
 01 WX-REGISTRO-SALIDA   PIC X(20).
*
************************************************************
 PROCEDURE DIVISION.
************************************************************
*  |     0000 - PRINCIPAL
*--|------------------+----------><----------+-------------*
* 1| EJECUTA EL INICIO DEL PROGRAMA
* 2| EJECUTA EL PROCESO DEL PROGRAMA
* 3| EJECUTA EL FINAL DEL PROGRAMA
************************************************************
 00000-PRINCIPAL.
*
     PERFORM 10000-INICIO
*
     PERFORM 20000-PROCESO
*
     PERFORM 30000-FINAL
     .
************************************************************
*  |     10000 - INICIO
*--|------------+----------><----------+-------------------*
*  | SE REALIZA EL TRATAMIENTO DE INICIO:
* 1| Inicialización de Áreas de Trabajo
* 2| Primera lectura de SYSIN
************************************************************
 10000-INICIO.
*
     INITIALIZE WX-SYSIN

                WX-REGISTRO-SALIDA
                WX-TABLA-NOMBRES

     ACCEPT WX-SYSIN FROM SYSIN

     PERFORM 11000-ABRIR-FICHERO
     .
*
************************************************************
*               11000 - ABRIR FICHEROS
*--|------------------+----------><----------+-------------*
* Abrimos el fichero de salida
************************************************************
 11000-ABRIR-FICHERO.
*
     OPEN OUTPUT FICHERO
*
     IF NOT FS-FICHERO-OK
        DISPLAY 'ERROR EN OPEN DEL FICHERO:'FS-FICHERO
     END-IF
     .
*
************************************************************
*  |     20000 - PROCESO
*--|------------------+----------><------------------------*
*  | SE REALIZA EL TRATAMIENTO DE LOS DATOS:
* 1| Realiza el tratamiento de cada registro recuperado de
* la SYSIN
************************************************************
 20000-PROCESO.
*
     MOVE WX-SYSIN TO WX-TABLA-NOMBRES
     MOVE 1        TO WI-INDICE

     PERFORM UNTIL WI-INDICE GREATER 4
        PERFORM 21000-INFORMAR-REGISTRO
        PERFORM 22000-ESCRIBIR-FICHERO

        ADD 1 TO WI-INDICE
     END-PERFORM

     .
*
************************************************************
*               21000 - INFORMAR REGISTRO
*--|------------------+----------><----------+-------------*
* MOVEMOS LA INFORMACION DESDE NUESTRA TABLA INTERNA A LA
* VARIABLE WX-REGISTRO-SALIDA
************************************************************
 21000-INFORMAR-REGISTRO.
*
     MOVE WX-NOMBRE(WI-INDICE) TO WX-REGISTRO-SALIDA

     .
*
************************************************************
*               22000 - ESCRIBIR FICHERO
*--|------------------+----------><----------+-------------*
* ESCRIBIMOS EN EL FICHERO DE SALIDA LA INFORMACION GUARDADA
* WX-REGISTRO-SALIDA
************************************************************
 22000-ESCRIBIR-FICHERO.
*
     WRITE REG-FICHERO FROM WX-REGISTRO-SALIDA

     IF NOT FS-FICHERO-OK
        DISPLAY 'ERROR EN WRITE DEL FICHERO:'FS-FICHERO
     END-IF

     .
*
************************************************************
*  |     30000 - FINAL
*--|------------------+----------><----------+-------------*
*  | FINALIZA LA EJECUCION DEL PROGRAMA
************************************************************
 30000-FINAL.
*
     PERFORM 31000-CERRAR-FICHERO

     STOP RUN
     .
*
************************************************************
*  |     31000 - CERRAR FICHERO
*--|------------------+----------><----------+-------------*
*  | CERRAMOS EL FICHERO DE SALIDA
************************************************************
 31000-CERRAR-FICHERO.
*
     CLOSE FICHERO

     IF NOT FS-FICHERO-OK
        DISPLAY 'ERROR EN CLOSE DEL FICHERO:'FS-FICHERO
     END-IF
     .


En el programa podemos ver las siguientes divisiones/secciones:
IDENTIFICATION DIVISION: existirá siempre.
ENVIRONMENT DIVISION: existirá siempre.
  CONFIGURATION SECTION: existirá siempre.
  INPUT-OUTPUT SECTION: en este ejemplo existirá porque utilizamos un fichero de salida.
DATA DIVISION: existirá siempre.
  FILE SECTION: en este ejemplo existirá pues utilizamos un fichero de salida.
  WORKING-STORAGE SECTION: exisitirá siempre.
  En este caso no exisistirá la LINKAGE SECTION pues el programa no se comunica con otros programas.
PROCEDURE DIVISION: exisitirá siempre.


En el programa podemos ver las siguientes sentencias:
PERFORM: llamada a párrafo
INITIALIZE: para inicializar variable
ACCEPT: esta sentencia recoge la información del campo indicado en el "FROM". En este caso recoge la información almacenada en "SYSIN"; la que nosotros hemos introducido en el JCL.
OPEN: "Abre" los ficheros del programa. Lo acompañaremos de "INPUT" para los ficheros de entrada y "OUTPUT" para los ficheros de salida.
DISPLAY: escribe el contenido del campo indicado en la SYSOUT del JCL.
MOVE/TO: movemos la información de un campo a otro
PERFORM UNTIL: bucle
ADD:Operador de adición (suma)
WRITE: Escribe la información indicada en el "FROM" en el fichero indicado.
STOP RUN: sentencia de finalización de ejecución.
CLOSE: "Cierra" los ficheros del programa.

Descripción del programa:
En el párrafo de inicio, inicializamos las variables que utilizaremos a lo largo del programa:
WX-SYSIN: donde guardaremos posteriormente mediante un ACCEPT la información que hemos escrito en la SYSIN del JCL.
WX-TABLA-NOMBRES: donde moveremos la información de la SYSIN para dividirla en los diferentes nombres.
WX-REGISTRO-SALIDA: donde guardaremos la información que vamos a escribir en el fichero de salida.
Abriremos el fichero de salida (OPEN OUTPUT) y controlaremos el file-status. Si todo va bien el código del file-status valdrá '00'. Podéis ver la lista de los file-status más comunes.

En el párrafo de proceso, informamos la tabla interna WX-TABLA-NOMBRES, donde el campo WX-NOMBRES se repetirá 4 veces (occurs 4 times). Recordad que el tratamiento de las tablas internas está explicado en detalle en el ejemplo 1.
Montaremos un bucle para escribir cada uno de los nombres guardados en la tabla interna en el fichero de salida.
Informaremos la variable WX-REGISTRO-SALIDA con cada uno de los nombres de la tabla.
Escribiremos el fichero de salida. Para ellos indicaremos a continuación del WRITE la variable definida en la FILE-SECTION, y a continuación del FROM la variable donde tenemos guardada la información que queremos escribir.
Controlaremos el file-status.

Nota: es importante controlar el FILE-STATUS en los accesos a ficheros (OPEN, READ, WRITE, CLOSE...) para, en caso de fallo en la ejecución, tener información sobre la causa del error.