Desarrollando en Cobol y Natural sobre Plataforma Mainframe

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.

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.

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.

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.

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.

miércoles, 20 de noviembre de 2013

Obtención de Listado de fichero DB2

Para la obtención de un listado de los elementos contenidos en un fichero DB2 deberemos hacer uso de la sentencia FETCH y disponer de un tabla de variables en la que podamos almacenar toda la información que vayamos recuperando del fichero.

En primer lugar, necesitaremos un proceso en el que se vaya recuperando toda la información del fichero DB2 y cargándola en una tabla. Una vez finalizado dicho proceso, incluiremos una rutina que vaya procediendo a leer los datos de la tabla y los vaya mostrando por pantalla.



Esto sería algo así:

     PERFORM 1000-INICIO     
     THRU    1000-INICIO-EXIT  

*
     PERFORM 2000-PROCESO        
     THRU    2000-PROCESO-EXIT   
     UNTIL   FIN-ENTRADA1        
*

     PERFORM 3000-LISTADO        
     THRU    3000-LISTADO-EXIT     


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 último registro disponible en el fichero 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                                                
*                                                                
*    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 3 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º) 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 leídos del fichero DB2 (MAX-REG).

 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-REG.                
*                                        
 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, obtener un listado de datos a partir de su lectura y mostrar dicha información por pantalla.

Un problema típico que puede aparecer en estos casos se produce cuando las ocurrencias de la variable Tabla no son suficientes para almacenar todos los registros que existen en el fichero DB2.

En esos casos habría que recurrir a lo que se denomina proceso de Paginación, que consiste en llenar la variable Tabla con datos del fichero DB2, mostrarlos por pantalla, vaciar dicha Tabla y volver a llenarla con los siguientes datos recuperados del DB2 (y así iterativamente hasta llegar al final del fichero DB2). Pero la implementación de este proceso ya la veremos otro día en otro post.

Saludos.

miércoles, 6 de noviembre de 2013

Utilización de Variables de Indicador Nulo

Cuando intentemos recuperar un valor NULL de un campo de una tabla DB2 y almacenarlo en una variable del programa Cobol, nuestro compilador nos devolverá un error SQLCODE 305. Para subsanar este problema precisaremos del empleo de una Variable de Indicador Nulo (Null Indicator Variable).

De forma estándar, la sentencia FETCH sólo puede recuperar valores no nulos de los campos de las tablas DB2. Sin embargo, es posible que en nuestro programa queramos trabajar con registros que contengan NULL en alguno de sus campos. Aquí es donde entraría en juego la Variable de Indicador Nulo.



Normalmente, una sentencia FETCH se definiría del siguiente modo:

EXEC SQL                                    
  FETCH CUR_JJCLIEM0                        
    INTO                                    
         :S-CLIENTE,                        
         :S-NOMBRE,                         
         :S-APELLIDO1,                      
         :S-APELLIDO2,                      
         :S-ALTURA,                         
         :S-PESO,                           
         :S-IMC,                            
         :S-OBSERVACIONES, 
         :S-FECHA                           
END-EXEC
                                     

Y, en general, no tendría que haber problemas. Pero imaginemos que accedemos a un registro cuyo campo OBSERVACIONES tiene valor NULL. Entonces, esta sentencia no podría cargar dicho valor en la variable S-OBSERVACIONES y se produciría un error SQLCODE 305.

Para evitar este problema tendríamos que declarar en nuestro programa una Variable de Indicador Nulo que iría asociada a la variable S-OBSERVACIONES. Por ejemplo, podríamos definir una variable denominada I-OBS del siguiente modo.

01 VAR-INDICADOR-NULO.             
  05 I-OBS           PIC S9(4) COMP.

*

Es importante destacar que la Variable de Indicador Nulo debe tener el formato indicado, es decir, debe ser de tipo S9(4) COMP.  En caso contrario, se producirá un error en la fase de compilación.

Una vez definida la variable, hemos de proceder a declarar la sentencia FETCH incorporando I-OBS a continuación de I-OBSERVACIONES (usando los datos del ejemplo anterior). Por supuesto, este formato sería el mismo independientemente del nombre de las variables.

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    
                                

Como vemos, a continuación de la variable S-OBSERVACIONES se incluye la cláusula INDICATOR. Finalmente, se añade el nombre de la Variable de Indicador Nulo, precedido del literal ":". En el caso del ejemplo, vemos que se ha añadido INDICATOR :I-OBS.

:S-OBSERVACIONES INDICATOR :I-OBS

Con este simple cambio, nuestro FETCH ya permitirá recuperar el valor NULL del campo OBSERVACIONES del registro y lo trasladará a la variable S-OBSERVACIONES.

Al mismo tiempo que se se extrae la información del registro DB2, se cargará un valor en la Variable de Indicador Nulo, en función de la información recogida en el campo asociado. Los posibles valores de la Variable de Indicador Nulo serán los siguientes:

a) '0': el valor del campo no es nulo.
b) '-1': el campo de la tabla DB2 tiene valor NULL.
c) '-2': el valor del campo ha sido truncado.

Por tanto, tras el acceso a la tabla DB2 podremos verificar si el campo tenía un valor NULL simplemente con validar el contenido de la Variable de Indicador Nulo. Esto podría hacerse del siguiente modo, siguiendo con el ejemplo de I-OBSERVACIONES e I-OBS.

IF I-OBS < 0
  DISPLAY 'CAMPO EXTRAIDO CON VALOR NULL'
END-IF

Y eso sería todo con respecto a este tema. Como vemos, el tratamiento de las Variables de Indicador Nulo es bastante sencillo, pero tendremos que recordar no olvidar toda su implementación si alguna vez queremos trabajar con valores NULL de campos de tablas DB2.

Saludos.

Related Posts Plugin for WordPress, Blogger...