Desacoplamiento de RPG database IO utilizando Rational Open Access:

Un nuevo comienzo para RPG, ILE, y SQL

Pasar de una DDS a una base de datos SQL en DB2, se puede lograr sin cambiar una sola línea de código de programa o volver a compilar un programa.En este artículo se describe cómo utilizar Rational Open Access: RPG Edition para aprovechar las técnicas avanzadas de programación centrada de datos sólo disponibles a través de la programación SQL.

Daniel R. Cruikshank, Senior Consultant, IBM

Cruikshank photoDan cuenta con más de 39 años de experiencia en la industria de TI, sobre todo con los sistemas de IBM Rochester y RPG. Dan también tiene más de 20 años de experiencia en SQL. Actualmente es profesor de técnicas de programación de Data Centric y DB2 for i Optimization a través del Lenguaje de consulta estructurado incorporado. Dan es especialista en la resolución de problemas de rendimiento de aplicaciones y reingeniería de bases de datos.



02-04-2012

Código de muestra de RPG Open Access

El código de muestra de RPG Open Access se encuentra disponible ahora online en: http://ibm.com/systems/i/db2/db2code.html

Los clientes de IBM i, en todo el mundo están ahora utilizando SQL para definir y tener acceso a los datos.Con cada nuevo release, IBM continúa ofreciendo nuevas funciones y posibilidades que sólo se pueden explotar con SQL.Se describe una lista de estas mejoras en el libro blanco DB2 Modernization.

Estas nuevas aplicaciones basadas en SQL se están aprovechando de los modernos conceptos de desarrollo centrado de datos que subrayan la importancia de impulsar más las normas empresariales y la lógica en las bases de datos.

Muchos de estos clientes siguen confiando en las aplicaciones del legado escrito en el lenguaje de programación RPG de IBM.Varios de estos programas RPG también se beneficiarían de la utilización de las modernas técnicas centradas de datos.Estas aplicaciones RPG existentes contienen las mismas normas empresariales que las nuevas aplicaciones de SQL, sin embargo, fueron escritas hace muchos años utilizando los registros tradicionales menos eficientes en ese tiempo en métodos de acceso de datos.La duplicación de las reglas y la lógica puede (y hace) dar como resultado el costoso doble mantenimiento y múltiples versiones de la verdad.

Entre en el Rational Open Access: RPG Edition o ROA.Este soporte (introducido con IBM i 7.1 y adaptado para soportar 6.1) puede eliminar el alto costo del doble mantenimiento y/o costoso volver a escribir el programa permitiendo interceptar y transformar en SQL las operaciones ES de RPG. Ahora se puede añadir una nueva palabra clave (HANDLER) a una especificación de archivo RPG existente. La palabra clave de manejador especifica un programa o un punto de entrada de programa de servicio el cual se llama a través del sistema operativo de IBM i. Este nuevo soporte puede reducir sustancialmente la cantidad de código antiguo que hay que escribir que puede ser necesario para convertir los programas existentes para compartir módulos comunes. Un ejemplo de código del manejador se muestra en El Listado 1.

Listado 1: Ejemplo de codificación de la palabra clave HANDLER
     FEMPADDRSL1UF   E           K DISK
      //-------------------Rational Open Access Addition ----------------------
      // The handler keyword specifies the program/service program which will
      // now process the IO operations for this file
     F                                     handler('UPDHANDLER')

En este artículo describiré cómo crear un manejador basado en el formato que permite múltiples programas los cuales actualizan la misma tabla utilizando un formato común y una clave única, para aprovecharse de una sola sentencia genérica SQL UPDATE que utiliza un soporte ampliado de variable del indicador.

Utilizaré el enfoque que se describe a continuación:

  • Crear un programa del manejador basado en el formato que intercepta registros tradicionales RPG a la vez que operaciones de base de datos ES. El programa del manejador convertirá la operación ES interceptada a las sentencias SQL equivalentes.
  • Activar un programa no-SQL RPG ILE existente para utilizar el programa del manejador añadiendo una sola línea de código.
  • Crear y registrar un procedimiento de almacenado externo que permita a cualquier interfaz (Java, PHP, etc.) que soporta llamadas a procedimientos almacenados para acceder al programa del manejador

He elegido el estilo de formato libre RPG IV como mi lenguaje de programación basado en host.Esto se debe principalmente al hecho de que pienso que el uso de Rational Open Access: RPG Edition parecerá más atractivo para el programador de RPG.Sin embargo, es importante tener en cuenta que el manejador y los programas de SQL se pueden escribir en cualquier lenguaje basado en host compatible con IBM i.

También me he tomado algunas libertades con los ejemplos de código, consolidando procedimientos, moviendo y eliminando código, etc. Esto podría dar lugar a que los ejemplos de código no se compilen como deberían.Además, algunos ejemplos de código sólo funcionarán si se instala el Rational Open Access.

Compilación desde un programa del manejador basado en el formato

Existen dos métodos para transferir datos de ida y vuelta entre el programa RPG y el programa del manejador por medio de Rational Open Access.El primero se basa en la estructura, mientras que los datos y valores claves se transmiten por medio de almacenamientos intermedios.Estos almacenamientos intermedios pueden ser descritos por medio de un programa o descritos externamente.El segundo método se basa en columnas, donde los datos y valores claves se transmiten como elementos individuales.Cada elemento contiene los atributos de los datos o campos clave.El método que se utiliza tiene una relación directa sobre el número de manejadores que pueden ser necesarios escribir.En cualquier caso, se necesitará el uso del SQL incorporado dinámico para minimizar el esfuerzo de codificación y el número total de programas de los manejadores.

El SQL dinámico es un candidato ideal para la creación de manejadores de base de datos genéricos.Existen tres tipos de manejadores de bases de datos genéricos que usted puede comenzar a implementar en función de su nivel de experiencia con ILE y SQL. Los tres tipos son el formato, la sentencia o manejadores basados en procedimientos. El manejador basado en el formato se presta muy bien a si mismo al estilo de lista fija del SQL dinámico. El manejador basado en la sentencia es más adecuado para el estilo de lista de variables del SQL dinámico. El manejador basado en el procedimiento se utiliza mejor para el conjunto de resultados de consumo o sentencias SQL tipo "uno y listo" tales como MERGE.

Por lo general se utiliza una lista fija de SQL dinámico cuando una aplicación ofrece la posibilidad de cambiar de forma dinámica la selección de filas (a través de la cláusula WHERE) o una columna de pedido (a través de la cláusula ORDER BY), sin embargo el conjunto de resultados proyectado es estático. En la aplicación del manejador, se puede utilizar la lista fija del SQL dinámico con el método basado en la estructura. No es necesario un descriptor de SQL cuando se utiliza la fija la lista del SQL dinámico.

La lista de variables del SQL dinámico se utiliza normalmente cuando una aplicación compila la sentencia SQL entera desde cero. En este caso, se necesita un descriptor de SQL para describir la sentencia de SQL, las columnas proyectadas en el resultado se establecen junto con los parámetros de entrada. Existen dos tipos de descriptores, uno creado a través del SQL ALLOCATE DESCRIPTOR y el otro se define sobre la base de la estructura SQLDA. Se utilizará una lista de variable de SQL con los manejadores basados en la sentencia. Para obtener más información sobre el SQL dinámico, la consulte la guía de programación SQL online en: http://ibm.com/systems/i/db2/books.html

En este artículo, utilizaré una combinación de lista fija de SQL dinámico y de SQL incorporado estático (en la sentencia UPDATE) para crear un manejador basado en el formato. En futuros artículos, proporcionaré el cómo hacer la sentencia y los manejadores basados en procedimientos.

Uno de los mayores beneficios de utilizar el producto ROA es que elimina el costoso tiempo y esfuerzo de modificar y probar un programa existente. Este enfoque al desacoplamiento ES puede proporcionar un "nuevo inicio" a los desarrolladores ocupados de mantener el código GPG existente, el cual puede que no esté bien estructurado o aproveche las posibilidades proporcionadas por el modelo de programación ILE (Entorno de lenguajes integrados).

La Figura 1 proporciona una visión general de cómo el programa del manejador ofrece un puente a un conjunto de procedimientos existentes que se basan en el SQL para acceder a los datos. Estos procedimientos pueden ser procedimientos externos almacenados que utiliza SQL incorporado o escritos completamente en SQL PL. En este artículo utilizaré sub-procedimientos de RPG a través de SQL incorporado.

Figura 1: Utilización de un manejador para desacoplamiento de ES
Figura 1: Utilización de un manejador para desacoplamiento de ES

El manejador utiliza ILE para proporcionar una interfaz de prototipo al programa RPG. Con el fin de utilizar un manejador, el programa RPG existente debe ser un programa ILE también conocido como RPG IV. Por lo tanto, si un programa RPG existente no es ILE, entonces el primer paso sería convertir el programa RPG a ILE. Esto se logra mediante el uso del comando Convert RPG Source (CVTRPGSRC).

Mi programa manejador se compone de un módulo principal que dirige la operación RPG a un módulo del manejador correspondiente. Esto permite personalizar el módulo principal con el tipo de aplicación. Por ejemplo, un manejador para archivos solamente de entrada no necesita los módulos de actualización.

Los módulos individuales del manejador contienen la lógica para transformar la operación ES de RPG a la alternativa SQL correspondiente. El código de transformación se encuentra en los sub-procedimientos. Además, los módulos del manejador contienen las llamadas prototipo a un programa de servicio RPG SQL que contiene los sub-procedimientos SQL incorporados. En la actualidad hay 19 bases de datos relacionadas con las operaciones ES de RPG que eventualmente necesitan ser manipuladas por el programa del manejador. En mi ejemplo de programa del manejador, estoy usando cuatro de ellos, OPEN, CHAIN, UPDATE y CLOSE.

La Figura 2 contiene el Rational Visualize Application Diagram que representa el caso de ejemplo anterior. El procedimiento principal del manejador, UPDHANDLER, suaviza la operación ES de RPG de entrada al sub-procedimiento correspondiente. El sub-procedimiento lleva a cabo la lógica de transformación antes de llamar al sub-procedimiento del programa de servicio SQL RPG correspondiente.

Figura 2: RDP Visualize Application Diagram
Figura 2: RDP Visualize Application Diagram

Vista aumentada de la Figura 2.

El Procedimiento principal del manejador (UPDHANDLER)

El manejador basado en el formato tiene que definir el formato de registro del archivo que está siendo manipulado. Esto se consigue mediante la codificación de las plantillas para la definición del archivo, el formato de registro de archivo, las claves de archivo y la matriz del indicador de nulo de SQL como parte del módulo del manejador como se muestra en El Listado 2. Estos están codificados como variables RPG globales para permitir la reutilización posterior de los nombres de plantilla genéricos y minimizar la modificación del código.

Listado 2: Definición de la plantilla de formato de registro
     FrcdFile_t IF   E           K DISK    TEMPLATE
     F                                     EXTDESC('EMPADDRESS')
     F                                     RENAME(empAddr:rcdFormat)

     D rcdFormat_t...
     D                 DS                  LIKEREC(rcdFormat)
     D                                     TEMPLATE

     D keys_t          DS                  LIKEREC(rcdFormat:*KEY)
     D                                     TEMPLATE

     D Ind_Array_t...
     D                 S              5i 0 DIM(7)
     D                                     TEMPLATE

El Listado 2 contiene un ejemplo de código de la definición de una plantilla de archivo. La palabra clave TEMPLATE, nueva en IBM i 6.1, informa al compilador de RPG que este archivo se utilizará solamente para la definición de campo, por lo tanto no se requieren o se permiten en este archivo operaciones de ES. No se requiere la palabra clave EXTDESC. En este caso, se utiliza para definir el archivo real que contiene la definición del formato de registro utilizado en el programa del manejador.

La palabra clave RENAME se utiliza para proporcionar un nombre de formato genérico para reducir los cambios del código que debe utilizar este código como una plantilla para otros manejadores de formato. Esto se puede ver en la plantilla de estructura de datos rcdFormat_t la cual está basada en el formato renombrado. Esta plantilla de estructura de datos se utiliza en otros módulos dentro del programa del manejador.

La matriz de indicador de nulo de SQL se utiliza en los sub-procesos RPG HANDLE_CHAIN y RPG HANDLE_UPDATE.Los valores del indicador de nulo se llenan durante la ejecución de la sentencia FETCH en SQL. Los valores de indicador nulo se establecen por medio del sub-procedimiento RPG HANDLE_UPDATE previo a la ejecución de la sentencia UPDATE en SQL.

Una vez que se especifica la palabra clave de manejador de un archivo, todas las operaciones de ES explícitas o implícitas ejecutadas en contra de ese archivo son ahora manipuladas por el programa del manejador. Es responsabilidad del programador el codificar las instrucciones necesarias para procesar la operación de ES y proporcionar los resultados adecuados. El producto ROA se envía con un RPG include file (QRNOPENACC), que contiene las definiciones de subcampo del parámetro que se transmite al programa del manejador.

El Listado 3 contiene un ejemplo del procedimiento principal en el programa UPDHANDLER. El parámetro de entrada (rpgIO) es una estructura de datos definida como la plantilla QrnOpenAccess_t que forma parte del módulo incluirQRNOPENACC. El procedimiento principal actúa en los siguientes subcampos:

  • El campo rpgStatus es utilizado por la entrada y la salida para indicar éxito o fracaso. Un cero indica que la operación tuvo éxito. El manejador suministra un código de estado de archivo válido si se produce una excepción. Los códigos de estado se definen en el Manual de referencia ILE RPG.
  • El campo rpgOperation contiene un código que corresponde a la operación de RPG que se llevó a cabo a través del programa RPG que estaba siendo manipulado. El módulo include proporciona constantes con nombre para cada código de operación de ES (es decir, QrnOperation_OPEN, QrnOperation_CHAIN, etc.).El programa RPG selecciona los controles de sentencia cuyo sub-procedimiento se ejecutará en base a la operación de RPG. La estructura de datos rpgIO se transfiere a cada sub-procedimiento y el campo rpgStatus se utiliza como un campo de retorno. Si un sub-procedimiento establece rpgStatus a 1299 a continuación se produce un error irrecuperable y el manejador se desactiva (INLR* está activado).
Listado 3: Ejemplo de código RPG del procedimiento principal del manejador
     D UPDHANDLER      PI
     D rpgIO...
     D                                     LIKEDS(QrnOpenAccess_T)
      /COPY QOAR/QRPGLESRC,QRNOPENACC
      /FREE

       rpgIO.rpgStatus = *Zero;

       select;
         when rpgIO.rpgOperation = QrnOperation_OPEN;
                rpgIO.rpgStatus = Handle_Open(rpgIO);
         when rpgIO.rpgOperation = QrnOperation_CHAIN;
                rpgIO.rpgStatus = Handle_Chain(rpgIO);
         when rpgIO.rpgOperation = QrnOperation_UPDATE;
              rpgIO.rpgStatus = Handle_Update(rpgIO);
         when rpgIO.rpgOperation = QrnOperation_CLOSE;
              rpgIO.rpgStatus = Handle_Close (rpgIO);
         Other;
       ENDSL;

       //If unrecoverable error then shutdown handler
       If rpgIO.rpgStatus = 1299;
         *INLR = *On;
       ENDIF;
       return;
      /END-FREE

La interfaz de sub-procedimiento

Cada sub-procedimiento de operación de ES de RPG, utiliza una interfaz común que consiste en el parámetro rpgIO y un campo de retorno que corresponde al código rpgStatus. Además, cada procedimiento establece rpgStatus a cero a la entrada y utiliza el dispositivo RPG Monitor para gestionar errores inesperados. Cuando se produce un error, el campo rpgStatus se establece a 1299 (Otro error de E/S detectado). Esto provoca una excepción en el programa RPG que está siendo manipulado.

El listado 4 contiene un fragmento del código de la interfaz de sub-procedimiento del manejador común.

Listado 4: Prototipo de la interfaz de sub-procedimiento común
     P Handle_Open     B
     D Handle_Open     PI                  LIKE(rpgIO.rpgStatus)
     D rpgIO...
     D                                     LIKEDS(QrnOpenAccess_T)

     D* Local fields
     D retField        S                   LIKE(rpgIO.rpgStatus)
          
      /FREE
       retField = *Zero;
       Monitor;
      //routine specific data and code begins here
       On-Error;
          retField = 1299;
       ENDMON;

       RETURN retField;

      /END-FREE

     P Handle_Open     E

Manipulación de operaciones abiertas de RPG implícitas y explícitas

Se puede producir un archivo abierto RPG implícitamente durante la fase de inicialización de RPG, o explícitamente a través de la operación de RPG OPEN y el uso de la palabra clave USROPN en la definición del archivo. En la mayoría de los casos, la apertura de implícito será suficiente. El uso de la operación OPEN explícita proporciona más interacción entre el programa RPG y el manejador.

Lo primero que se debe hacer en la rutina OPEN del manejador es establecer los punteros y las longitudes de las estructuras de los datos de Información de retroalimentación de ES. Estas son las estructuras que se pueden utilizar en un programa RPG cuando se producen errores inesperados. Le permite enviar información de estado adicional de vuelta al programa RPG. El Listado 5 contiene un fragmento de código para el establecimiento de estos valores en la estructura de datos rpgIO.

Listado 5: Información de retroalimentación de ES
        rpgIO.openFeedback = %Alloc(80);
        rpgIO.ioFeedback = %Alloc(160);
        rpgIO.deviceFeedback = %Alloc(126);
        rpgIO.openFeedbackLen = 80;
        rpgIO.ioFeedbackLen = 160;
        rpgIO.deviceFeedbackLen = 126;

El siguiente elemento de importancia es el puntero rpgIO stateInfo. Este puntero opcional se utiliza para asignar el almacenamiento temporal donde usted puede almacenar la información que necesita retener entre las llamadas al y desde el manejador. Uno de estos objetos es una imagen antes de grabar. El programa de manejador compara la imagen antes de grabar con los valores transmitidos al manejador desde la operación de actualización de RPG.Veremos más sobre esto en el debate de sub-procedimiento de manipulación-actualización.

El Listado 6 contiene un ejemplo de código de declaración de una estructura de información de estado y a continuación la asignación de almacenamiento para el puntero stateInfo basado en el tamaño de la estructura.

Listado 6: Ejemplo de código para la estructura de datos stateInfo
      //stateinfo data structure template
     D rpgSI_t...
     D                 DS                  TEMPLATE
     D  OLD_ROW_p                      *     
      /FREE  
       rpgIO.stateInfo = %Alloc(%Size(rpgSI_t));

En este punto, estamos dispuestos a construir la sentencia SQL que se utiliza para devolver el registro de entrada en respuesta a la operación RPG CHAIN. Esta sentencia será una variable de tipo cadena que se transmite al sub-procedimiento Prepare_SQL_Statement. La Figura 3 detalla el proceso de manipulación de una operación de apertura de archivo implícita RPG, junto con fragmentos de código de las funciones principales. El nombre del archivo abierto por el programa RPG se transmite al manejador en la estructura rpgIO externalFile. Esta estructura consta de dos subcampos: la biblioteca y el nombre. Si la columna de la biblioteca contiene *LIBL, entonces sólo se utiliza el nombre del archivo externo en la tabla de referencia, de lo contrario se combinan las columnas de la biblioteca y los nombres para formar una tabla de referencia cualificada. La variable de la tabla de referencia se utiliza entonces para la cláusula FROM de la sentencia SQL Select. Cuando falla la llamada al sub-procedimiento RPG PREPARE_SQL_STATEMENT, se devolverá un valor rpgStatus de 1299 al programa RPG que está siendo manipulado. Esto se muestra en el fragmento de código que se encuentra bajo el icono de proceso HANDLE_OPEN en la Figura 3

Figura 3: Manipulación de operaciones abiertas RPG
Figura 3: Manipulación de operaciones abiertas RPG

Se añade una cláusula WHERE a la serie de sentencia Select que representa la columna o columnas que corresponden a los campos clave utilizados en la operación RPG CHAIN. En este ejemplo, EMPNO es la clave única de la tabla. En este momento el valor de EMPNO es desconocido por lo que se utiliza un marcador de parámetro (?)como marcador. Se proporcionará el valor real en la primera operación RPG de ES codificada. Se añade una cláusula FOR FETCH ONLY a la sentencia Select para evitar el bloqueo de registros y aprovechar el bloqueo automático de SQL.

Una vez completado el formateo de sentencia de SQL, se transmite al sub-procedimiento RPG PREPARE_SQL_STATEMENT. Los procedimientos de RPG que contienen las sentencias de SQL incorporadas, se crean normalmente como módulos separados y luego se utilizan para crear un programa de servicio. Este programa de servicio se puede enlazar con el programa del manejador en tiempo de compilación. El módulo de SQL también debe contener el código de la plantilla de formato como se muestra en El Listado 2. Además, como soporte al uso de indicadores ampliados de SQL, el módulo de SQL tiene que ser compilado con el * EXTIND en el parámetro OPTION del comando precompilador, o contener una sentencia SQL Set Option que especifique EXTIND(*YES). Se debe especificar la sentencia Set Option antes que ninguna otra sentencia SQL dentro del módulo.

La Figura 3 contiene un ejemplo de código RPG para el sub-procedimiento RPG PREPARE_SQL_STATEMENT que prepara una serie de sentencia de SQL dinámico (v_SQL_String), y si tiene éxito declara un cursor SQL para la sentencia de SQL preparada. La serie de sentencia SQL (p_SQL_String) se transfiere al sub-procedimiento RPG desde el sub-procedimiento RPG HANDLE_OPEN en respuesta a la operación RPG Open.

Manipulación de la operación RPG CHAIN

Antes de que un programa RPG actualice una fila a la cual se accede mediante una clave, se debe realizar una operación de lectura para bloquear la fila de un intento de actualización. El método RPG más común para realizar una lectura aleatoria por medio de una clave es la operación CHAIN. La Figura 4 detalla el proceso de manipulación de una operación RPG CHAIN junto con fragmentos de código de las funciones principales.

Figura 4: Manipulación de operaciones RPG CHAIN
Figura 4: Manipulación de operaciones RPG CHAIN

Cuando se utiliza el método de ES basado en la estructura, RPG creará el almacenamiento inicial para el almacenamiento intermedio de entrada y salida, junto con el almacenamiento del mapa de indicador de nulo. El parámetro rpgIO contiene indicaciones a estas áreas de almacenamiento. El sub-procedimiento RPG HANDLE_CHAIN ​define estructuras de datos como las plantillas globales definidas anteriormente. Los datos contenidos dentro de las estructuras se basan en las indicaciones proporcionadas por RPG. El Listado 7 proporciona los ejemplos de código de origen para las definiciones de la estructura de datos. La Figura 4 contiene una muestra del código de origen RPG para el sub-procedimiento RPG HANDLE_CHAIN.

Listado 7: Manipulación de RPG CHAIN
     D Handle_Chain    PI                  LIKE(rpgIO.rpgStatus)
     D rpgIO                               LIKEDS(QrnOpenAccess_T)     

     D i               S              5i 0
     D keys            DS                  LIKEDS(keys_t)
     D                                     BASED(rpgIO.key)
     D inpRcd          DS                  LIKEDS(rcdFormat_t)
     D                                     BASED(rpgIO.inputBuffer)
     D OLD_ROW         DS                  LIKEDS(rcdFormat_t)
     D                                     BASED(rpgSI.OLD_ROW_p)
     D rpgSI...
     D                 DS                  LIKEDS(rpgSI_t)
     D                                     BASED(rpgIO.stateInfo)
     D IndAry          S              5i 0 DIM(%elem(Ind_Array_t))
     D InpNullMap      S               N   DIM(%elem(Ind_Array_t))
     D                                     BASED(rpgIO.inputNullMap)

RPG establecerá al puntero inputBuffer a nulos una vez que el programa RPG recibe los datos. Con el fin de comparar las imágenes antes y después de grabar, el manejador debe hacer una copia del registro de entrada. El almacenamiento de la fila antigua se define como parte de la estructura de datos stateInfo descritos en El Listado 6.. Esto garantiza que los datos se conservan entre la CHAIN y las operaciones UPDATE posteriores.

Si la columna se define como capacidad nula, entonces se debe actualizar el mapa del indicador nulo como corresponde. RPG utiliza un campo de caracteres 1 (como un indicador) para determinar si una columna contiene valores vacíos. SQL utiliza un pequeño número entero que contiene un cero si la columna no está vacía o -1 si la columna contiene valores vacíos.

En SQL, no existe un equivalente para RPG CHAIN, por lo que han decidido utilizar la sentencia FETCH FIRST con un cursor como la alternativa correcta. Esto también explica el uso de las sentencias del cursor SQL PREPARE, DECLARE, OPEN y CLOSE.

Una escuela de pensamiento podría sugerir el uso de SELECT INTO como una alternativa a la operación CHAIN. En cierto modo es parecido a un programa RPG que utiliza CHAIN ya que implícitamente realiza la preparación de las funciones de abrir y cerrar; sin embargo las desventajas superan con creces esta posibilidad abreviada. Esta desventajas son:

  1. SELECT INTO debe devolver una única fila o falla. No existe garantía de que el programa RPG utiliza una clave única en CHAIN. En este caso la fila devuelta a RPG es dependiente de que claves duplicadas de manipulación de palabras clave DDS (LIFO (predeterminada), FIFO (Primero en entrar, primero en salir) y LCFO) se utilizaron al crear el archivo lógico codificado.
  2. El problema anterior se puede sortear mediante el uso de DISTINCT y una o más indicaciones de fecha y hora para simular FIFO (Primero en entrar, primero en salir) o LCFO, sin embargo DB2 utilizará un paso adicional para eliminar los duplicados. Esto podría dar lugar a una disminución importante en el rendimiento, debe de haber un gran número de valores de clave duplicados.
  3. Debido a que SELECT INTO devuelve una fila única, no se puede utilizar para otras operaciones de lectura de RPG. Mientras que se puede utilizar el FETCH para devolver 1 o más filas permitiendo el uso de un sencillo sub-procedimiento RPG para las operaciones CHAIN, READ o READE

La Figura 4 contiene una muestra del código fuente de RPG para el sub-procedimiento FETCH_FIRST_FROM_OPEN_CURSOR. El sub-procedimiento RPG HANDLE_CHAIN transmite la clave (o claves), el puntero inputBuffer y la matriz indicadora.

La clave (o claves) se utilizan para reemplazar el marcador de parámetro (o marcadores), los cuales se definieron como parte de la serie de sentencia SQL creada en el sub-procedimiento HANDLE_OPEN RPG. La Sentencia OPEN CURSOR se ejecuta como parte del proceso FETCH. Si el OPEN tiene éxito, entonces se ejecuta la sentencia SQL FETCH FIRST.La estructura inpRcd y los parámetros indAry contienen los resultados de un FETCH con éxito. La combinación de SQL OPEN y FETCH equivale a las instrucciones del sistema realizadas en nombre de RPG CHAIN. Básicamente, las posiciones OPEN en el índice y FETCH FIRST recuperarán la primera fila en base a la RRN proporcionada en el índice.

Después de la segunda ejecución de OPEN dentro de la misma sesión o trabajo, el cursor SQL se convertirá en reutilizable. Esto significa que las operaciones posteriores de SQL OPEN y CLOSE simplemente colocan de nuevo el cursor en la primera fila del conjunto de resultados. Este comportamiento se produce independientemente de si el programa RPG utiliza el indicador LR o no. Esto permite el uso continuado de LR como una herramienta de limpieza, evitando los altos costos de sobrecarga del SQL abierto y cerrado.

Manipulación de la operación RPG UPDATE

Para entender el sub-procedimiento RPG HANDLE_UPDATE, debemos comentar el concepto de soporte de la variable del indicador ampliado. Previo al DB2 para el release i 6.1, las sentencias SQL Update e Insert podrían utilizar una variable del indicador con un valor de -1 para establecer una columna de capacidad nula para el valor vacío. Con el soporte de la variable del indicador ampliado, introducido en 6.1, se pueden ampliar, actualizar e insertar las posibilidades por medio de los valores del indicador adicionales.

De mayor interés es la posibilidad de utilizar un valor del indicador de -7 para permitir una actualización para evitar la columna como si no formara parte de la sentencia UPDATE. Este apoyo le permite escribir un procedimiento de actualización genérico que se puede utilizar para cualquier transacción de actualización, independientemente de las columnas que están siendo actualizas. La Figura 5 detalla el proceso de manipulación de una operación RPG UPDATE junto con fragmentos de código de las funciones principales.

Figura 5: Manipulación de la operación RPG
Figura 5: Manipulación de la operación RPG

La matriz del indicador de actualización se inicia a -7 como se muestra en el fragmento de código de la Figura 5 del sub-procedimiento RPG HANDLE_UPDATE. Los valores de la OutputBuffer se comparan con los valores que se guardaron de la inputBuffer. La variable del indicador de la columna se establece a cero por cada valor que es diferente. Se puede añadir el código adicional para realizar una verificación y ver si el nuevo valor es un valor definido por el usuario que indica que el valor de la base de datos debe establecerse a NULL o al valor predeterminado definido por la columna. Si lo anterior es cierto, entonces la variable del indicador de esa columna se establece a -1, lo que da lugar a que la columna se actualiza con el valor vacío. Si lo anterior es cierto, entonces la variable del indicador de esa columna se establece a -5, lo que configura la columna con valor predeterminado para esa columna. Si los valores antiguos y nuevos son los mismos, entonces la variable del indicador se mantiene como -7 y la columna se ignora. El sub-procedimiento RPG HANDLE_UPDATE es de formato específico y debe ser personalizado para cada archivo.

Una vez se han comparado todas la columnas se ejecuta el sub-procedimiento RPG UPDATE_COLUMNS_USING_EXTENDED_INDICATORS. El sub-procedimiento RPG UPDATE_COLUMNS_USING_EXTENDED_INDICATORS acepta dos parámetros, updRcd y Ind_Ary. El parámetro updRcd contiene los valores (cambiados y sin cambios) para las columnas actualizables en la tabla. La columna Ind_Ary contiene la configuración del indicador de SQL ampliado.

La Figura 5 contiene una muestra del código de origen de RPG del sub-procedimiento RPG UPDATE_COLUMNS_USING_EXTENDED_INDICATORS. El nombre de la tabla utilizada en UPDATE es el nombre del archivo que contiene el formato utilizado en el Listado 2. En la estrategia IBM Data Access Reengineering, este archivo se conoce como el archivo sustituto. Para más información sobre modernización del acceso de datos consultar la web site DB2 for i.

Las variables del indicador no se pueden especificar utilizando la técnica de indexación de matrices. Se debe poner un nombre individual a cada variable del indicador. Para evitar esto, utilizo una estructura de datos para definir una variable del indicador con un nombre para cada elemento de la matriz. La estructura de datos se basa en la dirección de Ind_Ary. El Listado 8 contiene el ejemplo de código de origen de RPG para la redefinición de la matriz del indicador de entrada a una estructura de datos.

Listado 8: Procedimiento de actualización con indicadores ampliados
     D Update_Columns_Using_Extended_Indicators...
     D                 PI              N
     D  updRcd...
     D                                      LIKEDS(rcdFormat_t)
     D  Ind_Ary...
     D                                      LIKE(Ind_Array_t)
     D                                      DIM(%elem(Ind_Array_t))
     D* Local fields
     D retField        S               N

     D Ind_Ary_DS      DS                  BASED(Ind_Ary_Ptr)
     D   Ind_Ary_1                    5i 0
     D   Ind_Ary_2                    5i 0
     D   Ind_Ary_3                    5i 0
     D   Ind_Ary_4                    5i 0
     D   Ind_Ary_5                    5i 0
     D   Ind_Ary_6                    5i 0
     D   Ind_Ary_7                    5i 0

      /FREE
       Ind_Ary_Ptr = %Addr(Ind_Ary);

Manipulación de operaciones cerradas de RPG implícitas y explícitas

El programa del manejador debe realizar dos funciones: 1) cerrar el cursor de SQL y 2) desasignar la memoria utilizada por la estructura de datos stateInfo. La Figura 6 detalla el proceso de manipulación de una operación RPG CLOSE implícita y explícita junto con fragmentos de código de las funciones principales.

Figura 6: Manipulación de operaciones RPG CLOSE
Figura 6: Manipulación de operaciones RPG CLOSE

El programa RPG activa el indicador Last Record (*INLR) lo que da lugar a una operación CLOSE implícita frente al archivo manipulado. El manejador intercepta la operación RPG CLOSE y pasa el control al sub-procedimiento RPG HANDLE_CLOSE. La memoria asignada al puntero stateInfo se desasigna. Se emite una llamada al sub-procedimiento RPG CLOSE_SQL_CURSOR que contiene la sentencia SQL CLOSE incorporada.


Casos de ejemplo de implementación

Los siguientes casos de ejemplo se utilizaron para probar el código del manejador: 1) un programa tradicional de RPG que utiliza un 5250 Display File y 2) un procedimiento de almacenado externo que se llama desde una aplicación Java. El caso de ejemplo de 5250 es típico de muchas tiendas tradicionales de RPG, donde muchos programas tienen acceso a la misma tabla para su actualización. El caso de ejemplo de Java describe una técnica donde un solo procedimiento externo de almacenado se utiliza en tablas de actualizaciones frente a varias sentencias SQL UPDATE contenidas en muchas aplicaciones. El objetivo es tener un sólo punto de control para todas las actualizaciones en la misma tabla independientemente del punto de origen. Estos casos de ejemplo se describen en la Figura 7.

Figura 7: Aplicaciones mixtas que comparten manejadores comunes
Figura 7: Aplicaciones mixtas que comparten manejadores comunes

Básicamente, un solo programa del manejador basado en formato es capaz de servir varios programas RPG 5250 basados en host por medio de una variedad de métodos UPDATE. Esto incluye la actualización del fichero o formato de registro utilizando las estructuras de datos o la función RPG integrada %FIELDS. Además, una vez que se registra un programa RPG como un procedimiento externo almacenado, cualquier interfaz (Java, PHP, etc.)que soporte llamadas a procedimientos almacenados puede acceder al programa de manejador. Este enfoque de procedimiento externo almacenado también permite a las aplicaciones externas como un cliente de navegador, aprovecharse del soporte del indicador ampliado DB2 for i.

El Listado 9 contiene un ejemplo de código de la sentencia SQL CREATE PROCEDURE utilizada para registrar un programa de RPG como un procedimiento externo almacenado.

Listado 9: Ejemplo de código de un procedimiento externo almacenado
CREATE PROCEDURE TEST_UPDFIELDS (
      IN p_ADDRESS1 VARCHAR(30)
     ,IN p_ADDRESS2 VARCHAR(30)
     ,IN p_ADDRESS3 VARCHAR(30)
     ,IN p_CITY VARCHAR(15)  
     ,IN p_STATE VARCHAR(10)   
     ,IN p_ZIPCODE VARCHAR(10)
     ,IN Unique_Key CHAR(6)	)
	LANGUAGE RPGLE
	PARAMETER STYLE GENERAL WITH NULLS
	RESULT SETS 2
	NOT DETERMINISTIC
	MODIFIES SQL DATA
	EXTERNAL NAME RPGEXTPROC

El Listado 10 contiene el código para el programa de RPG existente que ha sido registrado como un procedimiento externo almacenado. Los códigos de operación de ES RPG que serán manipulados por el programa UPDHANDLER son BOLD. El programa RPG define el archivo sustituto para el intento de actualización. La clausula PARAMETER STYLE GENERAL WITH NULLS de la sentencia SQL CREATE PROCEDURE que aparece en el Listado 9 especifica que una matriz de indicadores de vacío será enviada como un parámetro adicional al procedimiento externo almacenado. Habrá un elemento en la matriz para cada parámetro de entrada transmitido al procedimiento externo almacenado. El programa RPG utiliza este parámetro (p_Ind_Ary) para determinar si el parámetro de entrada contiene un valor distinto de NULL (-1). En ese caso, la columna de datos correspondiente se cambia con el valor del parámetro de entrada. Puesto que el archivo EMPADDRESS está siendo manipulado por el programa UPDHANDLER, la operación UPDATE se procesa como se describe anteriormente en La Figura 5.

Listado 10: Ejemplo de código de un procedimiento externo RPG
     FEMPADDRESSUF   E           K DISK
     F                                     handler('UPDHANDLER')

     D i               S              5i 0

     D HandleTheInternet...
     D                 PR                  EXTPGM('RPGEXTPROC')
     D p_ADDRLINE1                         LIKE(ADDRLINE1)
     D p_ADDRLINE2                         LIKE(ADDRLINE2)
     D p_ADDRLINE3                         LIKE(ADDRLINE3)
     D p_CITY                              LIKE(CITY)
     D p_STATE                             LIKE(STATE)
     D p_ZIPCODE                           LIKE(ZIPCODE)
     D p_EMPNO                             LIKE(EMPNO)
     D p_Ind_Ary...
     D                                5i 0 DIM(7)

     P HandleTheInternet...
     P                 B
     D HandleTheInternet...
     D                 PI
     D p_ADDRLINE1                         LIKE(ADDRLINE1)
     D p_ADDRLINE2                         LIKE(ADDRLINE2)
     D p_ADDRLINE3                         LIKE(ADDRLINE3)
     D p_CITY                              LIKE(CITY)
     D p_STATE                             LIKE(STATE)
     D p_ZIPCODE                           LIKE(ZIPCODE)
     D p_EMPNO                             LIKE(EMPNO)
     D p_Ind_Ary...
     D                                5i 0 DIM(7)

     D inpRecord       Ds                  LIKEREC(EMPADDR:*INPUT)

      /Free
       Monitor;

        CHAIN(e) p_EMPNO  EMPADDRESS inpRecord;
        If %Found;

        If p_Ind_Ary(1) = *Zero;
          inpRecord.ADDRLINE1 = p_ADDRLINE1;
        ENDIF;
        If p_Ind_Ary(2) = *Zero;
          inpRecord.ADDRLINE2 = p_ADDRLINE2;
        ENDIF;
        If p_Ind_Ary(3) = *Zero;
          inpRecord.ADDRLINE3 = p_ADDRLINE3;
        ENDIF;
        If p_Ind_Ary(4) = *Zero;
          inpRecord.CITY = p_CITY;
        ENDIF;
        If p_Ind_Ary(5) = *Zero;
          inpRecord.STATE = p_STATE;
        ENDIF;
        If p_Ind_Ary(6) = *Zero;
          inpRecord.ZIPCODE = p_ZIPCODE;
        ENDIF;

        inpRecord.EMPNO = p_EMPNO;

        Update(E) EMPADDR inpRecord;

        ENDIF;

       On-Error;
       ENDMON;

       *INLR = *On; //Implicit CLOSE
       Return;

      /End-Free

     P HandleTheInternet...
     P                 E

Resumen

En este artículo se explica el concepto de utilizar Rational Open Access: RPG Edition para transformar registros tradicionales en un método de acceso de tiempo para aprovechar las técnicas más avanzadas de SQL como el soporte extendido variable del indicador, con tan sólo una línea de cambio de código en el programa RPG existente.

Con el soporte del indicador extendido, un solo programa puede utilizarse para todas las transacciones de actualización entrantes frente a una tabla única basada en una clave común. Esto incluye los programas existentes que utilizan métodos tradicionales de actualización e interfaces externas capaces de utilizar las llamadas a procedimientos almacenados. Esta técnica puede eliminar la necesidad de construir múltiples sentencias SQL las cuales actualizan un subconjunto de las columnas dentro de una tabla.

También presento el concepto de un manejador basado en el formato que le permite utilizar los almacenamientos intermedios de salida y entrada RPG como el mecanismo para mover datos entre el programa RPG y el manejador. El manejador basado en formato explota la posibilidad de la nueva plantilla de RPG IV. También se basa en el concepto de estructuras de datos descritos externamente, una forma de codificación flexible de las variables del lenguaje de host utilizado por la fija lista dinámica de SQL.

En futuros artículos, ampliaré estos conceptos mediante la creación del manejador sobre la base de la sentencia que funciona conjuntamente con la lista de variables dinámicas de SQL, la cual puede reducir sustancialmente el número de manejadores necesarios. Utilizaré estas técnicas para aprovechar las siguientes posibilidades avanzadas de SQL:

  • Técnicas de manipulación masiva de datos que utilizan los bloqueos de SQL FETCH e INSERT para superar las operaciones tradicionales (como por ejemplo, READE) que no pueden bloquearse.
  • Actualizaciones en masa que utilizan técnicas de buscado SQL UPDATE y DELETE
  • Sustitución de las técnicas tradicionales de archivo y purga de RPG con una sentencia SQL MERGE
  • Procedimiento almacenado de conjunto de resultados de consumo
  • Vistas actualizables de SQL Join utilizando el soporte INSTEAD OF TRIGGER

Todo lo anterior se puede utilizar con cambios mínimos en los programas existentes a través de los productos IBM Rational Open Access: RPG Edition.


Recursos

Se puede encontrar más información acerca de este producto en las siguientes web sites:

Para obtener más información acerca de DB2 para i, incluidos los libros blancos, educación y soporte, visite la web site DB2 for i

Para obtener más información acerca de la herramienta Rational Developer for Power Systems utilizada para crear el Visualizer Application Diagrams dentro de este artículo, y para descargar una copia de evaluación , visite la web site de descarga developerWorks Rational Tools

Para obtener el más actualizado, profundo conocimiento de la estrategia de modernización de DB2 for i Data Access, incluyendo experiencia práctica con Rational Open Access, Rational Developer for Power and Infosphere Data Architect, inscribirse en el DB2 for i Database Modernization Workshop en la siguiente web site: http://ibm.com/systems/i/db2/db2educ_m.html

Lecturas sugeridas

Para una mejor comprensión del concepto de archivo sustituto mencionado en este artículo, y la estrategia de IBM Database Modernization, revise el siguiente Redbook:

Visite el foro DB2 for i developerWorks para permanecer conectado, formular preguntas y encontrar soluciones.

Comentarios

developerWorks: Ingrese

Los campos obligatorios están marcados con un asterisco (*).


¿Necesita un IBM ID?
¿Olvidó su IBM ID?


¿Olvidó su Password?
Cambie su Password

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


La primera vez que inicie sesión en developerWorks, se creará un perfil para usted. La información en su propio perfil (nombre, país/región y nombre de la empresa) se muestra al público y acompañará a cualquier contenido que publique, a menos que opte por la opción de ocultar el nombre de su empresa. Puede actualizar su cuenta de IBM en cualquier momento.

Toda la información enviada es segura.

Elija su nombre para mostrar



La primera vez que inicia sesión en developerWorks se crea un perfil para usted, teniendo que elegir un nombre para mostrar en el mismo. Este nombre acompañará el contenido que usted publique en developerWorks.

Por favor elija un nombre de 3 - 31 caracteres. Su nombre de usuario debe ser único en la comunidad developerWorks y debe ser distinto a su dirección de email por motivos de privacidad.

Los campos obligatorios están marcados con un asterisco (*).

(Por favor elija un nombre de 3 - 31 caracteres.)

Al hacer clic en Enviar, usted está de acuerdo con los términos y condiciones de developerWorks.

 


Toda la información enviada es segura.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=90
Zone=Rational, Information mgmt
ArticleID=807261
ArticleTitle=Desacoplamiento de RPG database IO utilizando Rational Open Access:
publish-date=04022012