lunes, 12 de junio de 2017

Alocar ficheros dinámicamente con BPXWDYN

Hoy os traigo un ejemplo de cómo generar dinámicamente ficheros de salida a través de un programa cobol.
El BPXWDYN es una rutina del sistema, capaz de alocar/liberar/concatenar ficheros en una ejecución batch.

En este ejemplo, el programa lee de un fichero de entrada con N registros, y genera N ficheros de salida.
Para la nomenclatura, hemos utilizado un contador en uno de los delimitadores.

La utilidad? Imagina que tienes un fichero de entrada con 1 millón de registros, y tienes que generar un fichero de salida por cada uno de ellos (osea, 1 millón de ficheros). Vas a picarte el nombre de los ficheros a mano en el JCL? Además de que puede que no sepas el número exacto de registros que va a tener ese fichero, pues varíe cada día.
En fin, por si algún día os veis en la situación, aquí lo tenéis :-)

JCL:
//PASO01 EXEC PGM=PRUEBDYN
//ENTRADA   DD DSN=FICHERO.DE.ENTRADA,DISP=SHR
//SYSOUT   DD SYSOUT=*
//SYSTSPRT DD SYSOUT=*
//SYSPRINT DD SYSOUT=*

donde EXEC PGM= indica el programa SIN DB2 que vamos a ejecutar
SYSOUT DD SYSOUT=* indica que la información "displayada" se quedará en la cola del SYSOUT (no lo vamos a guardar en un fichero)
Para definir el fichero de entrada "ENTRADA" indicaremos que es un fichero ya existente y compartida al indicar DISP=SHR.

Fichero de entrada:
----+----1----+
REGISTRO1
REGISTRO2
REGISTRO3
REGISTRO4



PROGRAMA:

 IDENTIFICATION DIVISION.
 PROGRAM-ID. PRUEBDYN.
*==========================================================*
*     PROGRAMA QUE LEE DE FICHERO Y GENERA DINAMICAMENTE

*     VARIOS FICHEROS DE SALIDA
*==========================================================*

 ENVIRONMENT DIVISION.
*
 CONFIGURATION SECTION.
*
 SPECIAL-NAMES.
     DECIMAL-POINT IS COMMA.


 INPUT-OUTPUT SECTION.
*
 FILE-CONTROL.
 

*ENTRADA
 SELECT ENTRADA
 ASSIGN TO ENTRADA
 FILE STATUS IS FS-ENTRADA.
*SALIDA
 SELECT OTFILE ASSIGN TO OTFILE
 FILE STATUS FS.
*
 DATA DIVISION.
*
 FILE SECTION.
 

*ENTRADA
 FD ENTRADA
 LABEL RECORD STANDARD
 BLOCK CONTAINS 0 RECORDS
 RECORDING MODE IS F.
 01 REG-ENTRADA PIC X(80).

*SALIDA
 FD OTFILE.
 01 OT-REC PIC X(80).

*******************************************************

 WORKING-STORAGE SECTION.
 01 FS PIC X(02).
 01 FN PIC X(20).
 01 WS-ALLOC-STRING PIC X(100).
 01 PGM PIC X(08) VALUE 'BPXWDYN'.

 01 WS-VARIABLES.
    05 SW-FIN-ENTRADA PIC X(01) VALUE 'N'.
       88 FIN-ENTRADA VALUE 'S'.
       88 NO-FIN-ENTRADA VALUE 'N'.
    05 FS-ENTRADA PIC X(02).
    05 WS-ENTRADA PIC X(80).
    05 WS-NOMBRE-SALIDA.
       10 WS-PARTE-FIJA PIC X(13) VALUE
                                  'PARTE.COMUN.F'.
       10 WS-VARIABLE PIC 9(7).
    05 WS-LIBERAR PIC X(15) VALUE 'FREE FI(OTFILE)'.
******************************************************
 PROCEDURE DIVISION.
******************************************************

     PERFORM 100000-INICIO
     PERFORM 200000-PROCESO
       UNTIL FIN-ENTRADA
     PERFORM 300000-FIN

     .

*TRATO FICHERO DE ENTRADA
 100000-INICIO.
     OPEN INPUT ENTRADA

     IF FS-ENTRADA NOT EQUAL '00'
        DISPLAY 'ERROR AL LEER'
        PERFORM 300000-FIN
     END-IF

     PERFORM 110000-LEER
     .
*LEER FICHERO
 110000-LEER.
     READ ENTRADA INTO WS-ENTRADA

     EVALUATE FS-ENTRADA
         WHEN CTA-FS-CORRECTO

*Añadimos 1 a WS-VARIABLE para generar los diferentes
*nombres del fichero de salida
              ADD 1 TO WS-VARIABLE
          WHEN CTA-FS-FIN-FICHERO
              SET FIN-ENTRADA TO TRUE
          WHEN OTHER
              DISPLAY 'ERROR AL LEER'
              PERFORM 300000-FIN
    END-EVALUATE
    .

********************************************************

* PROCESO DEL PROGRAMA
* 1-MONTAMOS EL NOMBRE DEL FICHERO DE SALIDA
* 2-LLAMAMOS A BPXWDYN PARA ALOCAR
* 3-ESCRIBIMOS EN EL FICHERO DE SALIDA Y LO CERRAMOS
* 4-LLAMAMOS A BPXWDYN PARA LIBERAR EL FICHERO DE SALIDA
********************************************************
 200000-PROCESO.

    MOVE WS-NOMBRE-SALIDA TO FN

    STRING 'ALLOC DD(OTFILE) DSN(' FN ') NEW '
             'CATALOG ' 'LRECL(80) RECFM(FB)'
    DELIMITED BY SIZE
    INTO WS-ALLOC-STRING

*LLAMO AL PROGRAMA RARO
    CALL PGM USING WS-ALLOC-STRING

    DISPLAY 'SALIDA PGM:' RETURN-CODE
*ABRO FICHERO SALIDA
    OPEN OUTPUT OTFILE

    IF FS NOT EQUAL '00'
       DISPLAY 'ERROR AL ABRIR SALIDA:' FS
    END-IF

*ESCRIBO EN EL FICHERO
    MOVE WS-ENTRADA TO OT-REC

    WRITE OT-REC

    IF FS NOT EQUAL '00'
       DISPLAY 'ERROR AL ESCRIBIR SALIDA:' FS
    END-IF

*CIERRO EL FICHERO DE SALIDA
    CLOSE OTFILE

    IF FS NOT EQUAL '00'
       DISPLAY 'ERROR AL CERRAR SALIDA:' FS
    END-IF

    CALL PGM USING WS-LIBERAR

    PERFORM 110000-LEER
    .
*FIN
 300000-FIN.
    CLOSE ENTRADA

    IF FS-ENTRADA NOT EQUAL '00'
       DISPLAY 'ERROR AL CERRAR'
    END-IF

    STOP RUN

    .

La primera vez que llamamos al programa BPXWDYN, lo hacemos con la opción "alocar", ALLOC.
Le indicamos el nombre del fichero, lo que iría en la DSN, con una variable "FN" que contiene el nombre PARTE.COMUN.F0000001.
Además le indicamos las opciones que irían en el DISP: NEW, CATALOG. La longitud LRECL(80) y que es un fichero de longitud fija RECFM(FB).
Estas opciones podemos modificarlas en función de nuestras necesidades.

La segunda vez que llamamos al programa BPXWDYN es necesaria para que OTFILE coja el siguiente nombre que le asignemos. Si no lo hiciésemos, el primer nombre (PARTE.COMUN.F0000001) se quedaría alocado y no se generaría ningún otro.

El resultado son 4 ficheros de salida:
PARTE.COMUN.F0000001 --> contiene REGISTRO1
PARTE.COMUN.F0000002 --> contiene REGISTRO2
PARTE.COMUN.F0000003 --> contiene REGISTRO3
PARTE.COMUN.F0000004 --> contiene REGISTRO4

No hay comentarios: