Soporte de bases de datos DL/I

El código generado por EGL puede acceder a una base de datos Data Language/I (DL/I) en cualquiera de los siguientes sistemas destino: EGL permite el acceso de dos formas:

Tenga en cuenta que el código DL/I implícito y explícito utiliza una potente sintaxis pseudo-DL/I que presenta algunas diferencias con respecto al código DL/I real. Para obtener más información, consulte la directiva #dli.

Si no está familiarizado con DL/I, consulte la sección Conceptos básicos acerca de DL/I.

Sentencias de E/S de DL/I en EGL

La tabla siguiente muestra las sentencias de E/S de EGL que puede utilizar para acceder a bases de datos DL/I. La tabla incluye llamadas DL/I de ejemplo que cada palabra clave puede generar. Cuando se codifica una sentencia EGL add, por ejemplo, se genera una llamada DL/I ISRT. Puede previsualizar una versión no formateada de las llamadas DL/I que EGL generará colocando el cursor en una línea de código que contenga una palabra clave y pulsando sobre ella con el botón derecho del ratón. En el menú emergente, seleccione Sentencia DLI > Ver.

También puede codificar llamadas DL/I directamente, utilizando la sintaxis with #dli{ sentencia }. Esta sintaxis permite especificar con más detalle cómo debe acceder el programa a la base de datos, como es necesario si las llamadas DL/I por omisión generadas por EGL desde sentencias de E/S no son suficientes.

La lista siguiente muestra sentencias de E/S de EGL que soportan bases de datos de DL/I.

add
Coloca un registro de tipo DLISegment en una base de datos DL/I; o bien (si se utiliza una matriz dinámica de registros DLISegment), coloca un conjunto de registros bajo un solo segmento padre, n función del contenido de cada elemento de la matriz.
delete
Suprime un segmento de una base de datos. Primero debe utilizar una sentencia get...forUpdate, get next...forUpdate o get next inParent...forUpdate (generando una sentencia DL/I GHU, GHN o GHNP) para localizar y retener el registro.
get
Lee un único segmento de una base de datos; o bien (si utiliza una matriz dinámica de registros DLISegment), lee segmentos sucesivos de elementos sucesivos de la matriz. Si utiliza get para leer registros sucesivos de una matriz, el programa COBOL entrará en bucle en una serie de llamadas GN a continuación de la GU inicial.
get (...forUpdate option)
Lee y retiene un único segmento de una base de datos; o bien (si utiliza una matriz dinámica de registros DLISegment), lee segmentos sucesivos de elementos sucesivos de la matriz y los retiene (emitiendo una serie de llamadas GHN después de la GHU inicial).
get next
Lee el próximo segmento en función de la posición actual en la base de datos.
get next (...forUpdate option)
Lee y retiene el próximo segmento en función de la posición actual en la base de datos.
get next inParent
Lee el próximo segmento que tiene el mismo segmento padre, en función de la posición actual en la base de datos.
get next inParent (...forUpdate option)
Lee y retiene el próximo segmento que tiene el mismo segmento padre, en función de la posición actual en la base de datos.
replace

Vuelve a colocar un segmento cambiado en una base de datos. Primero debe utilizar una sentencia get...forUpdate, get next...forUpdate o get next inParent...forUpdate (generando una sentencia DL/I GHU, GHN o GHNP) para localizar y retener el registro.

En ningún caso se pueden actualizar varios segmentos de base de datos con una única sentencia EGL replace por omisión.

La sentencia de EGL set (específicamente la sentencia con la forma set record position) también soporta DL/I. Esta sentencia no realiza E/S pero localiza un segmento especificado en una base de datos. Para conocer detalles acerca del funcionamiento de la sentencia, consulte la sección dedicada a set.

Componentes de registro para soporte DL/I

Se crean los siguientes tipos de componentes de registro:
DLISegment
El componente de registro DLISegment corresponde a un segmento de una base de datos DL/I. Debe declarar una variable basada en ese componente y después utilizar esa variable para acceder al segmento.
PSBRecord
El componente PSBRecord contiene información relativa a un bloque de especificación de programa (PSB) de tiempo de ejecución e incluye un conjunto de registros cada uno de los cuales incluye a su vez detalles acerca de un bloque de control de programa (PCB) de tiempo de ejecución.

Debe declarar una variable basada en el componente PSBRecord y después asignar el nombre de variable a la propiedad psb del programa. EGL utiliza el registro para generar el código que crea y valida las llamadas DL/I.

Al trabajar con DL/I, el usuario también crea registros basados en los siguientes componentes de registro predefinidos, cada uno de los cuales coincide con el diseño de un PCB de tiempo de ejecución:
IO_PCBRecord
Un registro de este tipo permite a un programa comunicarse con un usuario a través de un terminal
ALT_PCBRecord
Un registro de este tipo permite a un programa cambiar el destino de un mensaje de salida.
DB_PCBRecord
Un registro de este tipo permite acceder a una base de datos DL/I
GSAM_PCBRecord
Un registro de este tipo se utiliza para acceder a un archivo por medio de (GSAM) (Método de acceso secuencial generalizado), en un programa generado para z/OS por lotes o BMP. El archivo actúa como una base de datos DL/I solo raíz y la salida se realiza por medio de un registro serie. Los compromisos y las retrotracciones afectan al archivo.

Dentro de cada registro PCB, se utiliza la propiedad compleja @PCB para definir el tipo y el nombre del PCB y, en algunos casos, la jerarquía de los segmentos visibles para dicho PCB. Para obtener detalles acerca de los tipos de registros, consulte las secciones Propiedades de un componente de registro PCB y Tipos y propiedades de registros.

Finalmente, puede declarar un registro fijo basado en el componente de registro predefinido PSBDataRecord. Puede utilizar el registro para interactuar con la variable de sistema DLILib.psbData, que contiene tanto el nombre del PSB de tiempo de ejecución como una dirección con la que se accede a dicho PSB. El registro es útil si necesita pasar el PSB (en realidad, un nombre y una dirección) a otro programa o recibir el PSB de otro programa.

Componente DLISegment

Cada tipo de segmento al que desee acceder en una base de datos DL/I debe tener un registro equivalente de tipo DLISegment en el programa.

Considere el ejemplo de base de datos de cliente y el código relacionado del Ejemplo de base de datos DL/I. Para cada cliente hay segmentos para el estado de crédito, historial y ubicaciones individuales. Cada ubicación tiene segmentos de pedido, y cada pedido tiene segmentos de elementos de línea. En este caso, creará registros de tipo DLISegment para Cliente, Crédito, Historial, Ubicación, Pedido y Elemento de línea.

A efectos de claridad, debido a problemas de migración o a conflictos con los convenios de denominación de EGL, puede que desee utilizar nombres diferentes en EGL y en DL/I para el nombres de segmento y los nombres de campos. Puede definir una o varias de las siguientes propiedades en un bloque de establecimiento de valor:
  • segmentName char(8) Si no ha utilizado el nombre de segmento DL/I para el nombre del registro DLISegment, especifique aquí el nombre de segmento de la base de datos. Por ejemplo, si tiene una base de datos DL/I que realiza el seguimiento de los estudiantes y uno de los tipos de segmento se denomina TRANSFER, no podrá utilizar ese nombre para un registro DLISegment en EGL, ya que EGL utiliza "transfer" como palabra clave reservada. En lugar de ello, puede denominar el registro DLISegment "xferStudents" y establecer segmentName="TRANSFER". EGL convierte todos los nombres a mayúsculas al generar el código fuente COBOL, por lo que custName en el código fuente EGL es equivalente a CUSTNAME en COBOL.
  • hostVarQualifier String EGL permite utilizar variables de lenguaje principal (variables definidas en el programa de lenguaje principal EGL en lugar de en DL/I) al construir directivas #dli. Estas directivas alteran temporalmente las llamadas DL/I por omisión que EGL genera desde palabras clave de E/S, como por ejemplo add o get.

    En ausencia de una directiva #dli, EGL crea argumentos de búsqueda de segmentos (SSA) por omisión para localizar segmentos DL/I específicos. Como se muestra en el ejemplo siguiente, la propiedad hostVarQualifier de un componente de registro DLISegment identifica un registro que contendrá un valor de clave utilizado en un SSA por omisión.

    Considere un caso en el que el segmento de cliente STSCCST es el padre del segmento de ubicación STSCLOC, y desea recuperar sólo los datos del segmento de ubicación. Al definir los tres componentes de registro para configurar el escenario, debe omitir (por ahora) la propiedad hostVarQualifier:
    Record CustomerRecordPart type DLISegment
    { segmentName="STSCCST", keyItem="customerNo" }
    	10 customerNo char(6)      { dliFieldName = "STQCCNO" };  //campo de clave
    	...
    end
    
    Record LocationRecordPart type DLISegment 
    { segmentName="STSCLOC", keyItem="locationNo" }
    	10 locationNo char(6)      { dliFieldName = "STQCLNO" };  //campo de clave
    	...
    end
    
    Record CustomerPSBRecordPart type PSBRecord { defaultPSBName="STBICLG" }
    	// PCB de base de datos
    	customerPCB DB_PCBRecord { @PCB {
    		pcbType = DB,
    		pcbName = "STDCDBL",
    		hierarchy = [
    			@Relationship { segmentRecord = "CustomerRecordPart" },
    			@Relationship { 
    				segmentRecord = "LocationRecordPart", parentRecord="CustomerRecordPart" },
    			...]}};
    end
    A continuación, debe asociar el programa con un registro basado en el componente PSBRecord y definir variables basadas en los componentes de registro:
    Program myProgram {
    	@DLI{ psb = "myCustomerPSB" }}
    
    	//definir variables
     myCustomerPSB CustomerPSBRecordPart;
     myCustomer CustomerRecordPart;
     myLocation LocationRecordPart;
    Finalmente, en una función, debe intentar recuperar el primer segmento de ubicación de la base de datos sin recuperar primero datos de cliente:
    	get myLocation;
    A partir de esta sentencia get, EGL generará el siguiente código pseudo-DL/I:
    GU STSCCST (STQCCNO = :CustomerRecordPart.customerNo) 
       STSCLOC (STQCLNO = :myLocation.locationNo)

    Observe que, aunque EGL ha asociado correctamente la variable myLocation con el segmento STSCLOC, EGL no ha podido encontrar la variable myCustomer. EGL sólo sabía que myLocation es de tipo LocationRecordPart, cuyo segmento padre es CustomerRecordPart, y que el keyItem de CustomerRecordPart es customerNo.

    Podría solucionar este problema dando a las variables el mismo nombre que los componentes de registro en los que se basan. Sin embargo, al hacerlo podrían producirse confusiones con facilidad, y es preferible utilizar nombres diferentes para los componentes y las variables. También podría codificar una directiva #dli en la que haya copiado el código pseudo-DL/I anterior y sustituido ":CustomreRecordPart" por ":myCustomer". En un tercer procedimiento más sencillo, puede añadir un hostVarQualifier a la declaración de CustomreRecordPart, del siguiente modo:
    Record CustomerRecordPart type DLISegment
    { segmentName="STSCCST", hostVarQualifier="myCustomer", keyItem="customerNo" }
    Ahora, la misma sentencia get producirá el código pseudo-DL/I correcto:
    GU STSCCST (STQCCNO = :myCustomer.customerNo) 
       STSCLOC (STQCLNO = :myLocation.locationNo)

    También podría utilizar la propiedad hostVarQualifier para hacer referencia a un campo de un registro que no se base en un segmento de la base de datos. Por ejemplo, si desea que EGL busque el valor de clave del segmento de cliente en un registro básico (como por ejemplo un registro de transacción), debe asignar el nombre de ese registro a la propiedad hostVarQualifier.

  • lengthItem FieldReference Si el componente de registro DLISegment define un registro de longitud variable, indique el campo del registro que especifica la longitud del registro.
  • keyItem FieldReference Si la base de datos especifica una clave para este segmento, identifique el campo que contiene el valor de clave. Como se ha indicado anteriormente, el campo puede estar en cualquier registro que elija, pero generalmente se encuentra en un registro basado en el componente de registro DLISegment que se define. EGL utiliza la propiedad keyItem para crear SSA por omisión.

Si está trabajando con un campo de registro DLISegment cuyo nombre no coincide con el nombre del campo de segmento de base de datos equivalente, establezca la propiedad de campo de registro dliFieldName en el nombre del campo de segmento.

Componente PSBRecord

El componente PSBRecord contiene información relativa al acceso del programa a una o varias bases de datos y se utiliza para suministrar acceso al PSB de tiempo de ejecución. Cada registro de ese tipo de componente incluye el siguiente campo:
  • defaultPSBName char(8). Identifica el PSB de tiempo de ejecución por el nombre. EGL asigna el valor de defaultPSBName al campo psbName es la variable de sistema DLILib.psbData. En CICS, esa asignación hace que el programa utilice el PSB de tiempo de ejecución especificado. El valor por omisión de defaultPSBName es el nombre del componente PSBRecord.

Componente PSBDataRecord

Este componente de registro predefinido es la definición de tipo para la variable del sistema DLILib.psbData. A un registro basado en el componente PSBDataRecord contiene los siguientes campos:
psbName char(8)
CICS utiliza este nombre para determinar el próximo PSB que debe planificarse. IMS no utiliza este nombre.
psbRef int
El campo psbRef proporciona acceso a la lista de PCB de tiempo de ejecución. No modifique este campo directamente.

En CICS, puede planificar el PSB identificado en psbName; la planificación se producirá después de que una operación de compromiso haya borrado psbRef. Para utilizar esta posibilidad, establezca psbRef en 0.

Declarar componentes de registro

El ejemplo siguiente muestra una forma de declarar un registro DLISegment que refleja un segmento de una base de datos DL/I:
Record CustomerRecordPart type DLISegment 
{ segmentName="STSCCST", keyItem="customerNo" }
	10 customerNo char(6)      { dliFieldName = "STQCCNO" };  //campo de clave
	10 customerName char(25)   { dliFieldName = "STUCCNM" };
	10 customerAddr1 char(25)  { dliFieldName = "STQCCA1" };
	10 customerAddr2 char(25)  { dliFieldName = "STQCCA2" };
	10 customerAddr3 char(25)  { dliFieldName = "STQCCA3" };
end

Para conocer los diseños de registro completos de esta base de datos de ejemplo, consulte la sección Ejemplo de base de datos DL/I.

Este tipo de declaraciones de registro describen la estructura de los segmentos de base de datos como visible para este programa. Durante la ejecución, el PCB de tiempo de ejecución determina lo que puede visualizar un programa individual.

La estructura de un registro debe coincidir con la estructura del segmento tal como DL/I lo presenta al programa. Defina los campos keyItem y lengthItem con la misma longitud y posición que tienen en el segmento DL/I. Si el segmento es un hijo lógico, la estructura debe incluir la clave concatenada del padre destino, así como los datos de intersección. Si el segmento es un segmento concatenado de una base de datos lógica, la estructura debe incluir la clave, los datos de intersección y el segmento padre destino.

E/S de base de datos

Debido a que las bases de datos DL/I son jerárquicas, el programa debe realizar el seguimiento de la ubicación actual dentro de la base de datos. Para localizar un segmento hijo específico, debe especificar el segmento padre de ese hijo (si existe), el segmento padre de ese padre (si existe) y así sucesivamente hasta llegar a la raíz de la base de datos.

Utilizando la base de datos de cliente como ejemplo, para poder trabajar con elemento de registro, debe establecer el cliente, la ubicación y los números de cliente de ese elemento. Afortunadamente, en EGL esto es muy sencillo. Suponiendo que haya definido correctamente los campos de todos estos registros, puede obtener un elemento de registro que desee actualizar de este modo tan sencillo:
	//crear instancias de los registros
	myCustomer CustomerRecordPart;
	myLocation LocationRecordPart;
	myOrder    OrderRecordPart;
	myItem     ItemRecordPart;

	//crear un argumento de búsqueda de segmento
	myCustomer.customerNo = "5001";
	myLocation.locationNo = "22";
	myOrder.orderDateNo = "20050730A003";
	myItem.itemInventoryNo = "CHAIR";   //clave compuesta de 1er componente
	myItem.itemLineNo = 27;
	
	//obtener el elemento y retenerlo
	try
		get myItem forUpdate;
		onException
			myErrorHandler(2);
	end

Durante la ejecución, DL/I realizará una llamada GU (get unique) con un argumento de búsqueda de segmento concatenado de 30 bytes que incluirá los campos de clave del cliente (6 bytes), pedido (12 bytes) y elemento (6 + 2 bytes).

Personalizar las sentencias DL/I

Dada una sentencia EGL que utiliza un registro DL/I como objeto de E/S, puede tratar esa sentencia de varias formas:
  • Puede aceptar la sentencia DL/I implícita. En este caso, los cambios efectuados en el componente de registro DL/I afectarán a las sentencias DL/I que EGL generará a partir del código. Si posteriormente indica que desea utilizar un elemento de registro diferente como clave de un segmento DL/I, por ejemplo, EGL recogerá automáticamente ese cambio durante la generación.
  • Puede convertir la sentencia en explícita ampliando la sentencia de E/S EGL con la sintaxis with #dli{ sentencia }. En este caso, los detalles de dicha sentencia DL/I se aíslan del componente de registro DL/I y los cambios subsiguientes que se realicen en el componente de registro DL/I no tendrán ningún efecto sobre la sentencia DL/I que se utilice durante la ejecución. Si se elimina una sentencia DL/I explícita del código fuente, la sentencia DL/I implícita (si existe) vuelve a estar disponible durante la generación. Para obtener más información, consulte la directiva #dli.
  • Puede cambiar el nombre del PCB incluyendo la palabra clave usingPCB y especificando un nombre de PCB sustituto en la sentencia de E/S EGL. Con dos PCB puede, por ejemplo, mantener dos punteros diferentes en la misma base de datos simultáneamente, lo que permite leer un segmento dos veces.
  • Puede sustituir la sentencia por completo y codificar llamadas DL/I explícitas mediante las funciones de biblioteca DLILib.AIBTDLI(), DLILib.EGLTDLI() o VGLib.VGTDLI().
Comentarios
(C) Copyright IBM Corporation 2000, 2005. Reservados todos los derechos.