Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Contenido
Sección 2 Fundamentos teóricos sobre RPG ILE.......................................................................1
Sección 3 SQL para IBMi-AS400 (Teoría)................................................................................69
Sección 4 SQL integrado en programas RPG ILE formato Free (Teoría)..................................86
Sección 5 Creación de pantallas en IBMi-AS400 (Teoría).....................................................109
Sección 6 Programación ILE en IBMi-AS400 (Teoría)............................................................112
Diseño estructurado
Comparaciones relacionales
· = (Igual a)
La instrucción Dcl-f (Declare file) describe cada archivo que usa el programa y
define como lo usa. El formato general de la instrucción Dcl-f es el siguiente:
Dispositivo
La entrada que sigue al nombre del archivo indica el dispositivo asociado con el
archivo. Los tres tipos de dispositivo más utilizados son las siguientes:
Uso de archivos
Una vez que haya definido una constante con nombre, puede usarla con
cualquier procesamiento apropiado para su tipo. El valor de una constante
nombrada es fijo, no puede cambiarlo durante el curso de la ejecución del
programa. Las constantes con nombre facilitan la comprensión de los
programas al eliminar literales cuyo propósito no es evidente.
Literales numéricos
–999.20
0123
555
10
+5
–10
3500
.88888
Literales de caracteres
'Juan Perez'
'Mno123 @15y'
'Valeria''s Pizza'
'12345'
'99%'
Literales tipificadas
Literal tipificada
Date
D'2000-04-16'
Tipo de dato
Literal tipificada
Time
T'09.55.10'
Tipo de dato
Literal tipificada
Timestamp
Z'2005-04-10-07.46.21.000000'
Tipo de dato
Literal tipificada
Hexadecimal
X'F1F1F1'
Definición de constantes
*Off
*On
*Hival
*Loval
*All
*Null
RPG permite asignar *Blank o *Blanks para hacer que una variable tipo caracter
se rellene con espacios en blanco. Asignar *Zero o * Zeros a variables
numéricas y de caracteres rellena las variables con ceros.
Las constantes figurativas *Off y *On representan valores de caracter "0" y "1".
*Off equivale a "0" y *On equivale a “1". Aunque puede utilizar *Off y *On con
cualquier variable de caracteres de cualquier longitud, los programadores
suelen utilizar *Off y *On para cambiar o comparar el valor de un indicador.
La asignación de *Hival rellena una variable con el valor más alto posible
apropiado para su tipo de datos. Asignarle a una variable tipo caracter *Hival
establece todos los bytes en FF hexadecimal. Para una variable numérica,
*Hival es el valor positivo máximo permitido para la representación de datos,
generalmente serán 9’s y un signo más (+). La asignación de *Loval rellena una
variable con el valor de clasificación más bajo posible apropiado para su tipo de
datos, por ejemplo, 00 hexadecimal para las variables tipo caracter y el valor
mínimo negativo para las variables numéricas. Los programadores a menudo
asignan *Hival o *Loval a una variable para asegurarse de que el valor de la
variable sea el máximo o el mínimo posible.
La constante *Null representa un valor nulo. Por lo general, se usa *Null para
representar la ausencia de cualquier valor, y esto no es lo mismo que usar
espacios en blanco o ceros. Por lo general, en ILE RPG se usa *Null solo en
situaciones inusuales.
Dcl-s VX Uns(5);
Dcl-s WHERESQL CHAR(256);
El nombre debe ajustarse a las reglas que gobiernan los nombres de los
elementos de datos, son las mismas reglas que se usan para la declaración de
constantes. El nombre debe reflejar el contenido de la variable. Los nombres de
los elementos de datos pueden tener hasta 4096 caracteres, pero es mejor
restringirlos a una longitud manejable. Si la variable se va a utilizar para referir a
un archivo descrito externamente, su nombre debe tener 10 caracteres o
menos.
Tipo de datos
Cuando una declaración define una variable como Char, está definiendo una
cadena de caracteres de longitud fija. El atributo de longitud se especifica entre
paréntesis. Todos los valores de la columna tienen la misma longitud en
memoria. Un valor que no ocupa toda la longitud se rellena con espacios en
blanco. La siguiente definición define NOMBRE, una variable de caracteres de
longitud fija de 75 caracteres (bytes) de longitud:
Datos numéricos
Recordemos que las variables con zona (o con signo) almacenan datos
numéricos, donde cada dígito ocupa un byte, y que las variables empacadas
usan solo medio byte para cada dígito. RPG permite ambos tipos de datos
numéricos:
Los números con zona son equivalentes al tipo de datos NUMERIC de SQL, y
los números empacados son los mismos que el tipo de datos DECIMAL en SQL.
Una variable numérica definida con INT es un entero con signo. Los enteros son
el medio más compacto de almacenar valores numéricos. La siguiente
declaración define un entero de cinco dígitos con signo, CONTROL:
La longitud entre paréntesis (que puede ser literal o constante) debe ser de 3, 5,
10 o 20 dígitos:
Dígito
Bytes
Valor Menor
Valor Mayor
-128
127
Dígito
Bytes
Valor Menor
Valor Mayor
-32,768
32,767
Dígito
Bytes
Valor Menor
Valor Mayor
10
-2,147,483,648
2,147,483,647
Dígito
Bytes
Valor Menor
Valor Mayor
20
8
-9,223,372,036,854,775,808
9,223,372,036,854,775,807
Los enteros no tienen decimales y tienen rangos limitados. Sin embargo, son un
tipo de datos eficiente y útil para datos numéricos. Un entero de cinco dígitos
en RPG es equivalente a SMALLINT de SQL, un entero de 10 dígitos en RPG es
equivalente a INT en SQL y un entero de 20 dígitos en RPG corresponde a
BIGINT.
Uns es una variación de los enteros con signo, Uns, define un entero sin signo.
Los enteros sin signo siguen los mismos principios que los enteros con signo,
excepto que sus valores son siempre positivos. La siguiente declaración define
CONTROL, un entero sin signo de cinco dígitos:
Los enteros sin signo tienen un rango de valores diferente de los enteros con
signo:
Dígito
Bytes
Valor Menor
Valor Mayor
255
Dígito
Bytes
Valor Menor
Valor Mayor
65,535
Dígito
Bytes
Valor Menor
Valor Mayor
10
4,294,967,295
Dígito
Bytes
Valor Menor
Valor Mayor
20
8
18,446,744,073,709,551,615
Los tipos de datos relacionados con fecha en RPG corresponden a los tipos de
SQL. Las siguientes declaraciones definen variables de fecha y hora llamadas
FECPAGO y HORA:
Para inicializar (es decir, asignar un valor inicial a) una variable, se especifica el
valor utilizando la palabra clave INZ (Inicializar) en la definición de la variable. El
valor inicial se indica mediante un literal, una constante o una constante
figurativa. En las siguientes definiciones se proporcionan valores iniciales a las
variables:
Otro valor de inicialización útil es *User, el cual se puede utilizar con campos de
caracteres si son al menos de 10 bytes de longitud. La codificación de Inz
(*User) para un campo de caracteres asigna el nombre del perfil de usuario
actual al campo de caracteres:
End-ds {ds-name};
DCL-DS CLIENTE;
id INT(10);
nombre CHAR(40);
fecInicio DATE(*ISO);
credito ZONED(11:2);
END-DS;
Las líneas para describir los subcampos que componen la estructura de datos
continúan después de la instrucción Dcl-ds. Definen cada entrada de subcampo
dándole un nombre. Es una práctica normal indentar la definición de
subcampos para mostrar una jerarquía de la estructura de datos fácilmente
visible. El orden de los subcampos debe representar sus posiciones relativas en
la estructura de datos. Después del nombre del subcampo, especifique una
palabra clave de tipo de datos. Cualquier tipo de datos permitido para variables
independientes también está permitido para subcampos de estructura de
datos.
Los subcampos numéricos que aparecen en las estructuras de datos suelen ser
de tipo zona, no empacados, debido a que una estructura de datos se considera
fundamentalmente una variable tipo caracter, los números con zona son
generalmente más flexibles porque cada dígito también es un caracter. Los
tipos de datos Packed, Int y Uns son válidos para subcampos numéricos si el
programa no necesita procesar la estructura de datos o sus subcampos como
datos de tipo caracter.
CodArea Zoned(3:0);
Central Zoned(3:0);
NumeroLoc Zoned(4:0);
End-ds telefono;
Sin la palabra clave Inz, todos los subcampos están inicialmente en blanco. El
programa finaliza de forma anormal si intenta realizar operaciones aritméticas
en CodArea, Central o NumeroLoc sin inicializarlas primero.
Dcl-proc loadScreen;
PIDPRODUCT = PRODUCTS.IDPRODUCT;
PDESCRIPT = PRODUCTS.descript;
PIDPRODTYP = PRODUCTS.idProdTyp;
PIDSUPPLR = PRODUCTS.idSupplr;
PUNITPRICE = PRODUCTS.UnitPrice;
PIDWREHOUS = PRODUCTS.idWrehous;
PIDBRAOFFI = PRODUCTS.idBraOffi;
PENTRYDTE = PRODUCTS.entrydte;
End-proc;
Observe que cuando la variable de resultado es más larga que el caracter literal
a asignar, el resultado se rellena con espacios en blanco incluso si ya contiene
otros datos. También se puede utilizar Eval* para asignar el contenido de un
campo de caracteres a otro del mismo tipo de datos. Se aplican las mismas
reglas con respecto al relleno y el truncado.
Dcl-S ID Char(2);
MATERIA = 'MAT01'; // VALOR DE MATERIA = 'MAT01'
*La palabra clave Eval de asignación se puede omitir para este tipo de
asignación.
Todas las variables de caracteres discutidas hasta ahora han sido variables de
caracteres de longitud fija con una longitud declarada específica. ILE RPG
también permite campos de caracteres de longitud variable. Al igual que una
variable de longitud fija, una variable de caracteres de longitud variable tiene
una longitud declarada, la cual es su longitud máxima. Pero las variables de
caracteres de longitud variable también tienen una longitud actual. La longitud
actual generalmente depende del valor de la variable, que puede cambiar
mientras se ejecuta el programa. Algunos procesos con cadenas de caracteres
son más eficientes con cadenas tipo Varchar que con cadenas tipo Char de
longitud fija.
Para definir una variable de caracteres de longitud variable, use la palabra clave
Varchar (o use la palabra clave Like para heredar las propiedades de una
variable de caracteres de longitud variable existente).
ILE RPG también admite muchas funciones integradas que puede utilizar con
expresiones de caracteres.
Observe que la función %Trim elimina solo los espacios en blanco en los
extremos del valor tipo caracter, no los que están dentro del valor. Por lo tanto,
las funciones de %Trim anteriores retienen el espacio en blanco dentro de ‘MUY
BIEN‘ al recortar los espacios en blanco de los bordes.
Como con todas las funciones, se usan separadores de dos puntos entre
argumentos. Puede representar la posición inicial y la longitud opcional
mediante el uso de variables numéricas, constantes o expresiones que
representen números enteros mayores a cero.
Los siguientes ejemplos ilustran cómo obtener una parte de una cadena de
caracteres:
El primer argumento (que puede ser una variable tipo caracter, literal o
expresión), proporciona la cadena de reemplazo para insertar en la cadena de
caracteres original, la cual es el segundo argumento que debe ser una variable
de tipo caracter.
%Xlate (Traducir)
outputString = %xlate(lowercase:uppercase:inputString);
Asignación numérica.
Los siguientes ejemplos demuestran cómo utilizar Eval para una asignación
numérica simple. En cada caso, el campo numérico que aparece a la izquierda
del signo igual recibe el valor que aparece a la derecha del signo. El valor de la
derecha puede ser un campo, literal o constante con nombre, pero debe estar
definido como numérico. No puede definir el campo de resultado dentro de la
declaración Eval; debe declararlo previamente en otra parte en el programa:
COMPRAS = *Zeros;
VALOR = *Loval;
VAR01 = VALOR ** 3;
Todos los valores de la expresión aritmética a la derecha del signo igual deben
ser, por supuesto, campos numéricos, literales o constantes. Otra restricción
surge cuando se utiliza la división en una expresión. un error de tiempo de
ejecución ocurre si en el momento de la división, el divisor (la parte de una
expresión inmediatamente a la derecha del signo de división) se evalúa como
cero.
hrsDiarias) * 1.5 ;
Para los tipos de expresiones, que utilizan la variable de resultado como primer
operando de la expresión, RPG ofrece varios operadores compuestos: + =, - =, *
=, / = y ** =. Estos operadores le permiten codificar este tipo de expresión
común de manera más concisa. Realizan la función aritmética solicitada,
utilizando la variable de resultado como primer operando de la operación. Por
ejemplo, con + =, la expresión es agregada a la variable de resultado. Las
siguientes expresiones son equivalentes:
VALOR01 = VALOR01 + 1;
// EQUIVALE A
VALOR01 += 1;
// EQUIVALE A
VALOR02 -= 1;
Redondeo
La sintaxis que usa ILE RPG para especificar que el redondeo toma lugar es
simple: solo ingrese una H entre paréntesis inmediatamente después del
código de operación Eval de la expresión cuyo resultado desea redondear. Los
siguientes ejemplos muestran el uso de la (H) con Eval:
Función numérica
%Rem(residuo)
A= 123;
B= 27;
Procesamiento de fechas
ILE RPG soporta tres tipos de datos que pueden almacenar y procesar valores
relacionados con fechas:
· Date
· Time
· Timestamp
La fecha y la hora son tipos de datos que se utilizan para almacenar valores
relacionados con un momento en el año (fecha) y un momento en el tiempo
(hora). Un timestamp es una combinación de una fecha y una hora.
Generalmente, ILE RPG aplica los mismos principios y reglas a los tres tipos de
datos.
Dcl-ds datosFact;
fechaVenta Date(*Iso);
End-ds;
Comprensión de los formatos de fecha
Cada uno de los tipos de datos relacionados con la fecha tiene un tamaño y
formato preestablecidos, y cada uno tiene un formato externo predeterminado
(*ISO), basado en los estándares de la Organización Internacional de
Normalización (ISO). El formato externo predeterminado para fechas es un
campo de 10 bytes con formato AAAA-MM-DD. La hora tienen una longitud
predeterminada de ocho bytes con formato hh.mm.ss. El formato externo
predeterminado para timestamp (Z) tiene una longitud de 26 bytes con formato
AAAA-MM-DD-hh.mm.ss.uuuuuu.
// myDate = '2004-05-01'
// myDate = '2004-05-04'
// myDate = '2004-06-04'
// myDate = '2002-06-04'
%Diff (diferencia)
En este formato, la primera fecha debe ser más reciente que la segunda fecha
(u hora). El resultado es un número (no redondeado, hasta un límite de 15
dígitos) y se descarta el residuo. Puede utilizar la función% Diff para encontrar
la duración entre:
● Dos fechas
El tercer argumento debe ser un valor especial que corresponda a una de las
siete duraciones:
dsply %char(valor);
dsply %char(valor);
Operaciones de iteración
Asumamos que queremos sumar los números entre 1 y 10. El uso de Dow
permite realizar fácilmente este caso, veamos el siguiente código:
dcl-s I INT(3);
I=0;
I += 1;
dsply %CHAR(I);
enddo;
// ESTE CICLO DESPLIEGA LOS VALORES DESDE 1 HASTA 10
dcl-s I INT(3);
I = 0;
DOU I = 9;
dsply %CHAR(I);
I += 1;
ENDDO;
Cuando el programa encuentra una operación Iter, el control pasa por alto las
instrucciones restantes en el ciclo y hace que comience la siguiente repetición.
Leave termina el proceso del ciclo por completo y envía el control a la
declaración que sigue inmediatamente a la declaración End del ciclo. Puede
usar una o ambas declaraciones con todas las operaciones iterativas (Dow,
Dou y For), pero no con las operaciones de selección (If, Select, etc.).
Ejemplo:
Dou %Eof;
Readc PGMSFL;
Select;
Leave;
VACTION = 'C' ;
MSG = VRESPONSE;
MSG = VRESPONSE;
OTHER;
Leave;
Endsl;
Enddo;
For
Select;
Rrn += 1;
Option = *BLANKS;
PDESCRIPT = VDESCRIPT;
PIDPRODUCT = VIDPRODUCT;
Sflend = *On;
Leave;
Endsl;
Endfor
Operaciones de selección
IF
If conditional_expression;
...
Endif;
If Not Exit;
Select;
loadScreen();
Exfmt PRODINQ;
MSG = ERROR;
Other;
MSG = OPERUNSUCC;
Endsl;
Endif;
ENDIF;
ENDIF;
Cuando se usa Or para trabajar con dos pruebas relacionales, If se evalúa como
verdadero si una de las condiciones (o ambas) es verdadera:
ENDIF;
Else
También puede incluir una operación Else dentro de un grupo If para configurar
una ruta alternativa de instrucciones que se ejecutarán en caso de que la
condición If sea falsa:
IF Sqlstate = Success;
PARM_MSG = SUCCESSOPE;
ELSE;
PARM_MSG = NOTSUCCOPE;
ENDIF
Anidamiento de grupos If
También se pueden anidar grupos If. Es decir, puede crear grupos If dentro de
otros grupos If, con o sin operaciones Else. Cada If requiere un Endif en el lugar
apropiado para indicar el punto final de la influencia de ese grupo de If. El
siguiente es un ejemplo con If anidados en ILE RPG:
IF PARM_ACT = 'A';
Chgmode = *Off;
Dltmode = *Off; // WAY TO TURN OFF AN INDICATOR
ELSE;
IF PARM_ACT = 'C';
Chgmode = *On;
Addmode = *Off;
Dltmode = *Off;
ELSE;
Dltmode = *On;
Chgmode = *Off;
Addmode = *Off;
ENDIF;
ENDIF;
When Exit;
Leave;
When AddProduct;
AddProd();
Clearsfl();
Loadsfl();
When Pagedown;
Loadsfl();
Clearsfl();
Loadsfl();
Other;
Readsfl();
Clearsfl();
Loadsfl();
Endsl;
LIKE
LIKEDS
Otra palabra clave, LIKEDS (como estructura de datos), define una estructura de
datos en base a otra estructura de datos, con los mismos subcampos:
NOMBRE VARCHAR(50);
CIUDAD VARCHAR(50);
NOORDENS INT(10);
END-DS INFOCLI;
Monitor;
// Code to monitor
On-Error *FILE;
On-Error *PROGRAM;
On-Error *ALL;
// Handles both program-error and file-error codes, from 00100 to 09999. This
is the
default.
EndMon;
Monitor;
Resultado = 0;
Endmon;
Llamada de programas
Programación modular
El flujo de control con una llamada es como el de una operación RPG Exsr
(ejecutar Subrutina), excepto que la llamada invoca un programa externo (o un
subprocedimiento) en lugar de una subrutina interna del programa. A la lista de
los programas activos en un trabajo se le llama pila de llamadas. Cada entrada
en la pila de programas (programa o procedimiento) tiene un nivel de llamada
que depende de su posición relativa con respecto a otras llamadas en la pila. El
primer programa tiene un nivel de llamada de 1, ese programa puede llamar a
otros programas los cuales estarán en un nivel de llamada de 2. Si alguna
entrada de nivel de llamada 2 realiza llamadas adicionales, esas llamadas
estarán en un nivel 3 y así sucesivamente. Cuando un programa de nivel de
llamada 3 termina, éste devuelve control al nivel de llamada 2. Similarmente,
cuando una entrada de nivel de llamada 2 termina regresa el control al nivel de
llamada 1.Y cuando un nivel de llamada 1 termina, el trabajo termina. El sistema
utiliza la pila de llamadas para monitorear el punto en el cual cada programa
debería regresar el control cuando cada uno termina.
Antes de que se pueda utilizar Callp para llamar un programa se debe definir
una interfaz para hacer la llamada. La interfaz básica de llamada incluye la
siguiente información:
PARM_PROD Char(5);
PARM_ACT Char(1);
PARM_MSG Char(40);
End-pr;
PARM_PROD Char(5);
PARM_ACT Char(1);
PARM_MSG Char(40);
End-pr;
*N Char(5);
*N Char(1);
*N Char(40);
End-pr;
Callp invoca al objeto del programa (tipo *PGM) asociado con el prototipo
declarado en el primer argumento requerido en la llamada y luego le pasa el
control. Enumere los parámetros entre paréntesis después del nombre del
prototipo:
*N Char(5);
*N Char(1);
*N Char(40);
End-pr;
……………….
Si los parámetros que pasa Callp no coinciden con el número, el orden y los
tipos de datos de los parámetros en la definición del prototipo, el programa no
se compilará. Si no hay parámetros, debe codificar paréntesis vacíos en su
lugar:
………….
sinParms ();
Este código llama a los programas asociados con sus respectivos prototipos, al
igual que en los ejemplos anteriores, la mayoría de los programadores
prefieren omitir la codificación explícita de la operación Callp, ya que esta
sintaxis coincide con operaciones de llamada similares a otros lenguajes
informáticos, como C o Java.
Return y *INLR
Dcl-s K Uns(2);
For K = 1 To 10;
EJEMPLO01 ();
Endfor;
*Inlr = *On;
Return;
*N Char(10);
*N Char(5);
*N Char(1);
End-pr;
Dcl-pi PROVAL_SQL; // Interface
End-pi;
*N Char(10);
*N Char(5);
*N Char(1);
End-pr;
Dcl-pi MAIN;
PARM_TABLE Char(10); // TABLE NAME
End-pi;
// PROGRAMA LLAMANTE
// ---- Prototypes
*N Char(10);
*N Char(5);
*N Char(1);
End-pr;
......
VRESULT = *BLANKS;
IF VRESULT = '1';
.....
// PROGRAMA LLAMADO
*N Char(5);
*N Char(1);
End-pr;
Dcl-pi PROVAL_SQL;
End-pi;
......
IF Sqlstate = SUCCESS;
PARM_RESUL = '1';
ELSE;
PARM_RESUL = '0';
ENDIF;
Después del retorno la variable VRESULT vale '1' o '0' y esto se debe a que
VRESULT y PARM_RESUL comparten la misma dirección en memoria.
*N Char(9) Const;
*N Packed(7:0) Const;
End-pr;
......
PRODACT('ABC' : VAR01);
......
También se puede codificar una expresión como parámetro al pasar por
referencia de solo lectura, en este ejemplo, el segundo parámetro es una
expresión:
*N Char(9) Const;
*N Packed(7:0) Const;
End-pr;
......
......
Se debe asignar un tipo de datos a cada columna de una tabla. El tipo de datos de la
columna determina cómo se almacenan sus valores, cuánto almacenamiento ocupa la
columna y qué tipo de operaciones se pueden realizar en la columna cuando se usa
dentro de un programa. Los tipos de datos de uso común se dividen en tres categorías
generales:
· Carácter
· Numérico
· Fecha
Todas las computadoras usan algún tipo de sistema de codificación para representar
caracteres como patrones de bits, pero no todos los sistemas usan EBCDIC, que es
único de algunos sistemas IBM. Es posible que ya esté familiarizado con el sistema de
codificación denominado ASCII (Código estándar americano para el intercambio de
información), generalmente pronunciado como as-kii. EBCDIC se desarrolló por
separado de ASCII. En consecuencia, los patrones de bits en ASCII no son los mismos
que en EBCDIC. Por ejemplo, la letra A en EBCDIC está representada por un hex C1,
pero en ASCII es un hex 41. Además, los dos esquemas utilizan diferentes secuencias
de clasificación; es decir, no clasifican todos los caracteres en la misma secuencia. En
EBCDIC, los caracteres en minúsculas se ordenan antes que los caracteres en
mayúsculas y las letras se ordenan antes de los números (por ejemplo, a, b, c,… A, B, C,
… 7, 8, 9). En ASCII es lo contrario (por ejemplo, 1, 2, 3,… A, B, C,… x, y, z).
Datos tipo carácter
Los datos tipo caracter pueden ser cualquier símbolo que el sistema soporte. Las letras
alfabéticas, los números y los caracteres especiales (por ejemplo, signos de puntuación,
símbolos de moneda) son todos datos de tipo caracter. Una cadena de caracteres es una
secuencia de caracteres. Un programa RPG normalmente procesa datos de tipo caracter
asignando valores de una variable tipo caracter a otra, concatenando (uniendo) cadenas
de caracteres o convirtiendo datos tipo caracter en otro tipo de datos.
Normalmente, cada caracter ocupa un solo byte en memoria. Pero algunos conjuntos de
caracteres usan dos bytes para almacenar cada caracter. Estos se conocen como
conjuntos de caracteres de doble byte y se utilizan con mayor frecuencia en idiomas
como el japonés o el chino que tienen más símbolos de los que se puede representar con
un byte. Las versiones extendidas de ASCII, llamadas Unicode y UCS (Conjunto de
Caracteres universal) también se han aceptado ampliamente. Estos conjuntos de
caracteres más nuevos, que se extienden más allá del alfabeto inglés, también son
conjuntos de caracteres de doble byte y tienen una gama mucho más amplia de
caracteres disponibles que EBCDIC o ASCII.
CHAR
Cuando SQL define una columna como CHAR (o CHARACTER), está definiendo una
cadena de caracteres de longitud fija. El atributo de longitud se especifica entre
paréntesis. Todos los valores de la columna tienen la misma longitud en memoria. Los
valores que no llenan toda la longitud se rellenan con espacios en blanco.
La mayoría de las columnas de caracteres en una base de datos de IBM i tienen una
longitud fija. Cuando no especifica una longitud, la columna es de un byte y la longitud
máxima es 32,766.
VARCHAR
Datos numéricos
SQL define datos numéricos con precisión y escala. La precisión se refiere al número
total de dígitos disponibles en el número sin tener en cuenta ningún signo. La escala
indica cuántos de esos dígitos son fraccionarios (es decir, a la derecha del punto
decimal).
NUMERIC
Especificar un tipo de datos NUMERIC (o NUM) define una columna como un número
decimal con zona (o con signo). Los números decimales con zona toman un byte
completo para almacenar cada dígito de un valor numérico. Por tanto, un número de tres
dígitos ocupa tres bytes. La zona del dígito más a la derecha almacena el signo de los
datos: 1111 (F) representa un valor positivo, mientras que 1101 (D) representa un valor
negativo. La representación por zonas, entonces, es casi idéntica a la representación de
caracteres, excepto que el signo está incrustado en el byte del dígito más a la derecha.
Bits (3 bytes)
Hex
+156
F1 F5 F6
Bits (3 bytes)
Hex
–156
F1 F5 D6
DECIMAL
Especificar un tipo de datos DECIMAL (o DEC) define una columna como un número
decimal empacado. Los números empacados toman ventaja de la redundancia que se
crea en la representación de dígitos, en este caso no se almacenan las zonas para los
números. En formato empacado, solo el dígito, o los bits de nivel inferior de un número
se almacenan y el signo se representa con 4 bits adicionales. Estos bits de signo siempre
ocupan las últimas cuatro posiciones de bits de un valor decimal empacado.
Bits (2 bytes)
Hex
+156
00010101 01101111
156F
Bits (2 bytes)
Hex
–156
00010101 01101101
156D
Un número de tres dígitos ocupa dos bytes. Puede que esto no parezca una gran
diferencia, pero números más grandes generan un mayor ahorro de memoria: un número
de 63 dígitos en formato empacado ocupa solo 32 bytes.
La mayoría de las columnas numéricas en una base de datos de IBMi son números
decimales empacados. Aunque algunos programadores prefieren definir columnas
numéricas con zona, porque es más fácil imprimir o ver los datos en este formato, la
computadora funciona de manera más eficiente con números almacenados en formato
decimal empacado. Para la mayoría de los procesos numéricos, RPG implícitamente
convierte valores numéricos a formato decimal empacado antes de procesarlos.
Ya se ha visto que los números decimales empacados son más compactos que los
números decimales con zona. La representación entera es incluso más compacta que la
representación decimal empacada. Los valores enteros se almacenan en formato binario.
A cada bit de una cadena se le asigna un valor decimal, y los valores de los bits se
suman para determinar el valor del signo del número. SQL admite tres tipos de datos
relacionados con números enteros. El que usted use dependerá del rango de valores que
se deben almacenar.
Tipo de Dato
Bytes
Digitos
SMALLINT
-32,768
32,767
Tipo de Dato
Bytes
Digitos
10
-2,147,483,648
2,147,483,647
Tipo de Dato
Bytes
Digitos
BIGINT
19
-9,223,372,036,854,775,808
9,223,372,036,854,775,807
Note que no es necesario indicar una precisión o escala. La precisión (10) se establece
por el tipo de datos INT y la escala para todos los enteros es 0.
DATE
Especificar un tipo de datos DATE define una columna como una fecha. Una fecha es
un valor de tres partes, que incorpora un mes, un día y año entre 0001 y 9999. Al definir
una fecha, no es necesario especificar una longitud porque el sistema la determina
automáticamente.
(aaaa- mm-dd)
· *JOB usa el formato especificado para el trabajo (use el comando DSPJOB para
determinar el formato de fecha actual del trabajo).
TIME
La especificación de un tipo de datos Time define una columna como una hora del día,
integrando horas, minutos y segundos. Los datos tipo Time siguen muchos de los
mismos principios que el tipo de datos Date. Al definir un dato tipo Time, no es
necesario especificar una longitud.
Un programa ILE RPG puede recuperar un valor tipo Time y procesarlo. Al igual que
con las fechas, la presentación de la hora en el programa se ajusta a cualquiera de los
cinco formatos de hora diferentes que utiliza un programa:
(hh.mm.ss)
· * JIS utiliza el formato de hora estándar industrial japonés (hh: mm: ss)
TIMESTAMP
Creación de tablas
Las declaraciones de lenguaje de definición de datos (DDL) se usan para crear objetos
nuevos, como tablas, y para alterar la estructura o propiedades de los objetos de base de
datos existentes.
Las tablas SQL contienen los datos de la base de datos. Cuando SQL crea una tabla
nueva, la base de datos crea un objeto de tipo archivo físico de un solo miembro en una
biblioteca. Las tablas están organizadas en filas (registros) y columnas (campos). SQL
usa la instrucción Create Table para crear una tabla:
Rcdfmt Prodrec
Esta declaración Create Table contiene tres cláusulas principales: (1) el nombre de la
tabla, (2) la estructura de sus columnas (es decir, sus campos) y (3) el nombre del
formato de registro.
Nombre de tabla
Definiciones de columna
Los siguientes son los tipos de datos más comunes que se utilizan con IBMi:
· DATE
· TIME
· TIMESTAMP
Además del nombre y el tipo de datos, cada definición de columna puede incluir
cláusulas de restricción opcionales para definir mejor la columna. Una restricción
especifica una regla para los datos de una tabla. Dentro de las cláusulas de restricción de
uso común se incluyen las siguientes:
NOT NULL
DEFAULT
UNIQUE
PRIMARY KEY
La restricción NOT NULL evita que la columna contenga valores nulos. Un valor nulo
representa la ausencia de datos para una columna. Se le pueden asignar valores nulos a
una columna que permita nulos en lugar de un valor real. La mayoría de las tablas de
IBMi especifican NOT NULL para cada columna, lo que obliga a esa columna a tener
siempre un valor.
La restricción DEFAULT indica que la columna debe contener un valor por defecto. El
valor por defecto se asigna a esa columna para todas las filas nuevas (registros) si no se
especifica ningún otro valor. Por ejemplo, para una columna que incluye la restricción
DEFAULT 99999, SQL asigna un valor de 99999 a esa columna a menos que la
instrucción SQL indique específicamente otro valor. Si la restricción no especifica un
valor por defecto, las columnas numéricas se rellenan con ceros, las columnas de
caracteres se rellenan con blancos y las columnas relacionadas con fechas usan el valor
de la fecha actual. Una columna que permite nulos, independiente de su tipo de datos
tiene un valor por defecto de nulo. Las definiciones de columna que omiten las
cláusulas NOT NULL y DEFAULT implícitamente se consideran con capacidad de
permitir nulos con un valor por defecto.
La restricción UNIQUE garantiza que cada fila en las tablas tenga un valor único para
esa columna. Una regla relacionada, PRIMARY KEY (clave principal), combina las
restricciones NOT NULL y UNIQUE. PRIMARY KEY asegura que una columna (o
combinación de dos o más columnas) contiene un valor único que identifica una fila
específica en la tabla. Una tabla solo puede tener una clave principal. Si la clave
principal consta de una sola columna, puede especificar la restricción de clave principal
en la definición de columna:
……..
Rcdfmt Prodrec
Rcdfmt Prodrec3
…….
Rcdfmt Prodrec3
Uno puede referirse a los objetos por un nombre simple, como PRODUCTS, o por un
nombre calificado. Un nombre calificado de un objeto incluye el nombre del esquema
(biblioteca) en el que se almacena el objeto. Dependiendo de la convención de
nomenclatura que se utilice, un nombre calificado de SQL podría ser:
Inserción de datos
VALUES ('A001',3000,600,200)
Analicemos la sintaxis. La primera parte es INSERT INTO, seguida de una lista de los
nombres de las columnas. La lista de columnas indica para qué columnas se estará
pasando información. En este caso, son las columnas IDPROD, QUANTITY,
INCOINV , OUTINV. La segunda parte de la declaración proporciona el valor para
cada columna. Esto se indica con VALUES seguidos de los datos de las columnas que
necesitan estar enumerados en el mismo orden que la lista de columnas. Tanto los
encabezados de columna como los valores de los datos deben estar entre paréntesis. Los
valores no numéricos deben ir entre apóstrofos. Tal vez desea utilizar la misma tabla
para una declaración de inserción, pero no desea incluir datos para cada columna; en
este caso, excluya la (s) columna (s) de la lista y SQL simplemente insertará un valor
nulo (o un valor por defecto si la columna no permite nulos) en cualquier columna de la
tabla que no esté en la lista del INSERT.
Borrado de datos
Nota: La consulta DELETE elimina datos de una tabla, pero no elimina la tabla en sí.
Para eliminar un objeto de base de datos y su contenido, se utiliza la declaración DROP,
por ejemplo, DROP TABLE PRODUCTS.
Actualización de datos
Hay casos en los que uno o más valores de columna necesitan ser actualizados en un
registro. Puede utilizar la sentencia UPDATE para modificar los valores de los registros
en una tabla:
Update INVENTORY
SET
QUANTITY = 5000
Este UPDATE establece el valor de 5000 para la columna QUANTITY solo para la fila
con un IDPROD cuyo contenido sea “A001". Si no se desea actualizar todos los
registros, asegúrese de incluir la cláusula WHERE. Pueden haber situaciones en las que
se desea actualizar cada registro de una tabla y, en esos casos, no se necesitaría una
cláusula WHERE.
Joins
Si necesita combinar o vincular datos de dos o más tablas diferentes en un solo conjunto
de resultados, puede usar JOIN para extraer datos de dos o más tablas usando un campo
común para vincularlos.
Hay múltiples tipos de JOIN disponibles. Un INNER JOIN devuelve todas las filas de
las tablas vinculadas donde se cumplen los criterios de coincidencia; las filas que no
coinciden no aparecen en el conjunto de resultados. Supongamos que desea obtener el
ID de Producto, la descripción del producto, el precio unitario del producto y el nombre
del proveedor que vende el producto. En el siguiente ejemplo, los campos idSupplr y
idSupp son campos para relacionar las tablas PRODUCTS y SUPPLIERS (llave
primaria y llave foránea), y se puede usar JOIN para vincular las tablas. Esta sería la
sintaxis SQL:
ON A.idSupplr = B.idSupp ;
En la parte del SELECT para cada nombre de columna se tiene un prefijo. Esto indica
de qué tabla recuperar la columna. Por ejemplo, B.SUPPNAME indica que se desea
recuperar la columna SUPPNAME de la tabla SUPPLIERS en la selección de
columnas. Después de SELECT, viene la sintaxis JOIN, que dice: Tomar la tabla
PRODUCTS y unirla con la tabla SUPPLIERS. Las columnas para hacer la
coincidencia son idSupplr y idSupp para este caso y se usan en la cláusula ON en donde
se hace uso del prefijo para indicar la tabla a la que pertenecen.
· LEFT OUTER JOIN: incluye todas las filas de la tabla de la izquierda y las filas de
la tabla de la derecha que tengan coincidencia con filas en la tabla de la izquierda, si hay
filas de la tabla de la izquierda sin coincidencia con filas de la tabla de la derecha, las
columnas de esa tabla (derecha) vendrán con nulos.
· RIGHT OUTER JOIN: incluye todas las filas de la tabla de la derecha y las filas de
la tabla de la izquierda que tengan coincidencia con filas de la tabla de la derecha, si hay
filas de la tabla de la derecha sin coincidencia con filas de la tabla de la izquierda, las
columnas de esa tabla (izquierda) vendrán con nulos.
Las vistas SQL proporcionan formas alternativas de acceder a los datos en una tabla.
Aunque un programa puede recuperar y procesar filas virtuales de una vista, la vista en
realidad no contiene datos. En cambio, almacena una ruta de acceso, una secuencia de
punteros a los datos reales en una o más tablas. Cuando SQL crea una vista nueva, la
base de datos construye un archivo lógico sin claves basado en un archivo físico. Un
programa RPG no hace distinción entre una tabla y una vista cuando procesa un
archivo. El programa puede leer y generalmente actualizar el archivo ya sea éste una
tabla o una vista. Los usos más comunes de una vista son seleccionar ciertas filas (un
subconjunto) de una tabla, seleccionar un subconjunto de columnas de una tabla o
seleccionar una combinación de ambas funciones. La declaración SQL Create View
crea una vista. La ruta de acceso se crea a partir de una sentencia SQL Select integrada
en la instrucción Create View:
AS
ON A.idSupplr = B.idSupp
ON A.idBraOffi = C.idBraOffi
ON A.idWrehous = D.idWrehous
RCDFMT RECVIEW
La sentencia Create View contiene tres cláusulas principales: (1) el nombre de la vista,
(2) una sentencia Select (más conocido como un fullselect) para seleccionar las filas y
columnas que estarán en la vista, y (3) el nombre de formato de registro de la vista. Un
fullselect es un componente de la instrucción Create View, especifica las filas y
columnas de una o más tablas que componen la vista. El fullselect declara las columnas
que se recuperarán, la tabla de la que se recuperarán y, opcionalmente, una cláusula
Where para especificar los criterios de selección de filas.
Tenga en cuenta que no se puede ordenar una vista, y tampoco el fullselect puede
contener la cláusula Order By.
Modificar una tabla (Alter Table)
La declaración SQL Alter Table realiza cambios estructurales en una tabla, cambiando
su formato. Los cambios que se pueden realizar con Alter Table son los siguientes:
Se elimina un constraint
Select
Insert
Update
Delete
Select
Insert
La instrucción SQL Insert agrega un registro (fila) a una tabla o vista. Se puede
comparar a la operación RPG Write. Una declaración de inserción simple tiene
la siguiente forma:
La cláusula Insert Into nombra la tabla. Después del nombre de la tabla, una
lista de columnas entre paréntesis para las que se proporcionarán los valores.
La cláusula Values proporciona valores para cada una de las columnas de la
lista de columnas. Debe especificar los valores en el mismo orden que la lista
de columnas y debe tener el mismo número de valores que las columnas. La
lista de columnas es opcional. Si lo omite, la instrucción Insert asume que
todas las columnas en el diseño del registro tienen los valores
correspondientes especificados en la cláusula Values. Si una columna tiene
permite nulos o se crea con un valor predeterminado, puede omitirla de la lista.
En ese caso, se utiliza el valor predeterminado o un valor nulo.
Update
El uso de la instrucción Update permite modificar una o más filas en una tabla.
Esta declaración corresponde a la operación Update de RPG combinada con la
función %Fields. La declaración de actualización sigue esta forma:
UnitPrice = 7777.75
Delete
La instrucción SQL Delete elimina uno o más registros (filas) de una tabla, de
forma análoga corresponde a la operación Delete de RPG, esta declaración
sigue esta forma:
Exec SQL
La directiva Exec SQL debe estar en una sola línea, pero la declaración SQL en
sí puede abarcar varias líneas. Al igual que con otras operaciones de RPG,
finaliza la instrucción SQL con un punto y coma (;):
SET
idProdTyp = '002',
idSupplr = '002',
UnitPrice = 999.99 ,
idWrehous = '002' ,
idBraOffi = '002' ,
entrydte = '2017-09-08'
SET
descript = :PDESCRIPT,
idProdTyp = :PIDPRODTYP,
idSupplr = :PIDSUPPLR,
UnitPrice = :PUNITPRICE ,
idWrehous = :PIDWREHOUS ,
idBraOffi = :PIDBRAOFFI,
entrydte = :PENTRYDTE
El nombre de la variable está precedido por dos puntos (:) y corresponde a una
variable de programa RPG. No es necesario definir la variable por separado
aparte de la variable RPG. Es el medio para permitir que la declaración SQL se
refiera a una variable RPG. Debe declarar la variable RPG con el mismo tipo de
datos y tamaño que la columna de base de datos asociada.
Las sentencias Insert y Delete también pueden usar variables Host para
sustituir valores de columnas:
Los nombres de variables Host no pueden comenzar con SQ, SQL, RDI o DSN.
Estos nombres están reservados para el uso de la base de datos.
Select Into
Exec SQL Select columns Into :host-variables From table {Where conditions};
La cláusula Into enumera las variables del programa en las que se colocará el
resultado de la consulta. Las columnas de la consulta y la lista de variables
Host del programa comparten una correspondencia de uno a uno; es decir,
debe haber una variable Host para cada columna del resultado de la consulta y
deben seguir el mismo orden. La consulta solo puede generar una fila. En
consecuencia, la cláusula Where a menudo refiere a la clave principal de la
tabla. Si el resultado de la consulta incluye más de una fila, SQL devuelve un
código de excepción.
DCL-DS PRODATA;
PRO_ID Char(5);
PRO_DESCRI Char(30);
END-DS;
FROM PRODUCTS
Al igual que con las variables Host, debe existir una correspondencia uno a uno
entre las columnas de la consulta y los subcampos en la estructura Host.
Una estructura de datos Host es especialmente útil para recuperar todas las
columnas de un formato de registro. En este caso, es apropiada una estructura
de datos descrita externamente. Analice el siguiente ejemplo:
FROM PRODUCTS
Dcl-ds Sqlca;
End-ds;
Sqlstate es similar a Sqlcode, pero mientras que los valores de Sqlcode pueden
ser exclusivos de IBMi, los valores de Sqlstate se establecen según los
estándares de la industria. Sqlstate tiene cinco caracteres; los dos primeros
caracteres indican una condición:
Sqlstate que comienza con 01 indica que la declaración fue exitosa, pero se
emitieron warnings.
Cualquier otra clase Sqlstate significa que la instrucción SQL no tuvo éxito.
Los valores de Sqlstate también se detallan en la documentación en línea de
IBM.
//----- CONSTANTS
IF Sqlstate = EOF;
PARM_MSG = NOT_FOUND;
.....
descript = :PDESCRIPT,
idProdTyp = :PIDPRODTYP,
idSupplr = :PIDSUPPLR,
UnitPrice = :PUNITPRICE ,
idWrehous = :PIDWREHOUS ,
idBraOffi = :PIDBRAOFFI,
entrydte = :PENTRYDTE
IF Sqlstate = SUCCESS;
PARM_MSG = SUCCESSOPE;
ELSE;
PARM_MSG = NOTSUCCOPE;
ENDIF;
.....
1. Declarar el cursor.
2. Abrir el cursor.
3. Recuperar filas.
4. Cerrar el cursor.
Un cursor SQL siempre está asociado con una instrucción Select para
establecer las filas a recuperar. La instrucción Select no se ejecuta de
inmediato, sino hasta que se abre el cursor. La instrucción Select puede incluir
variables Host y variables tipo indicador, que se sustituyen cuando el programa
abre el cursor.
Cuando se abre un cursor insensitive, el sistema crea una copia temporal del
resultado de la consulta y el programa trabaja con esa copia. Un cursor
insensitive no reconoce las inserciones, actualizaciones o eliminaciones
posteriores de éste o cualquier otro programa. El uso de un cursor insensitive
puede mejorar el rendimiento, pero es posible que el programa no siempre lea
los datos más recientes.
FROM PRODUCTS
Fetch requiere que nombre el cursor asociado con la consulta que desea
recuperar, y el cursor debe haber sido declarado y abierto previamente.
También debe nombrar las variables y estructuras que recibirán los valores de
las columnas. Este es un ejemplo:
Select *
From PRODUCTS
Hasta ahora, todas las declaraciones de SQL incrustado que hemos discutido
han sido SQL estático. Con SQL estático, la estructura básica de cada
instrucción SQL se conoce en el momento de la compilación del programa. La
declaración SQL puede usar variables Host para sustituir valores en tiempo de
ejecución, pero su propósito general y construcción no cambian una vez que se
crea el programa.
Prepare
Los programadores suelen utilizar SQL dinámico junto con cursores SQL. En el
siguiente ejemplo, la instrucción Prepare traduce el contenido de la variable
SQLSTRING, creando SQLcursor, que luego se utiliza para proporcionar la
instrucción Select incrustada para el cursor PRODCURSOR:
......
FLAG_CURSO = 1;
ELSE;
FLAG_CURSO = FLAG_CURSO + 1;
ENDIF;
Find = *Blanks;
ELSE;
ENDIF;
....................
Execute
Una vez que se ha preparado una sentencia, el programa puede ejecutar esa
sentencia muchas veces utilizando la instrucción SQL Execute. Si la declaración
incluye marcadores de parámetros, el programa puede sustituir un valor
diferente cada vez que se ejecuta la sentencia. La instrucción Execute toma
esta forma:
........
.......
Set Option
Closqlcsr = *Endpgm,
Commit = *None;
Alwcpydta
Closqlcsr
Closqlcsr (Cerrar cursor de SQL) especifica cuándo cerrar los cursores de SQL
si el programa no los cierra explícitamente con una instrucción Close. Esta
opción también determina el alcance de las sentencias SQL preparadas y los
bloqueos de archivos. Estas son opciones comunes:
Closqlcsr (*Endjob) permite que los cursores permanezcan abiertos hasta que
finalice el trabajo en el IBMi (AS/400).
Commit
Para crear un programa RPG que incorpore declaraciones SQL, se puede utilizar
un editor, como SEU o LPEX, para ingresar el código en un miembro de archivo
fuente. Sin embargo, a diferencia de los programas anteriores, que usaban un
tipo de miembro de RPGLE, si el programa incluye sentencias de SQL, el tipo de
miembro debería ser SQLRPGLE. Una vez que el miembro fuente contiene todo
el código requerido, se usa el comando de compilador CRTSQLRPGI (Crear
objeto RPG ILE SQL), para compilar el fuente y crear el programa (o módulo o
programa de servicio).
Una pantalla en AS/400 está compuesta de código que se conoce como DDS’s. En
versiones anteriores del AS/400 estas sentencias se usaron para construir las bases de
datos en donde las tablas se conocían como archivos físicos y las vistas se conocían
como archivos lógicos, además las DDS’s se usaron para crear archivos de pantalla y de
impresión que se conocen como archivos de dispositivo.
Hoy en día las DDS’s se continúan usando, pero con orientación a crear archivos de
dispositivos de pantalla o de impresión, siendo las pantallas las de más uso.
Una pantalla en AS/400 está compuesta de tres tipos de definiciones, una definición
corresponde a nivel de archivo y sus definiciones aplican para todos los formatos de
pantalla dentro del archivo, es como el contenedor para todo lo que se defina en relación
a formatos de pantalla, otro tipo de definición corresponde a formatos de pantalla y el
termino formato lo podemos asociar con una pantalla y la tercera definición corresponde
a las constantes y los campos que componen los formatos de pantalla.
Como hemos dicho, los archivos de pantalla están compuestos de código DDS, el cual
se podría codificar usando algún tipo de editor, sin embargo en este curso esa no va a
ser la orientación porque las pantallas las desarrollaremos usando la herramienta
Rational Developer for i (RDI) en forma gráfica y la gran ventaja es que la herramienta
crea el código en forma automática, en algunos momentos veremos el código y lo
usaremos para la compilación.
Los formatos de pantalla establecen que campos serán leídos, que campos serán para
despliegue o que campos serán para ambos fines.
Los campos de los formatos de pantalla pueden estar conectados a campos de una tabla ,
o pueden ser campos independientes de la tabla.
Para lograr la comunicación por medio de las teclas de función se hace uso de
INDICADORES, los indicadores fueron muy usados en versiones anteriores del
lenguaje RPG y los podemos comparar con el concepto de variable booleana, en donde
un indicador solo puede tener dos estados (encendido y apagado), los indicadores son
valores que están dentro del rango (01 - 99), actualmente se siguen usando dentro de los
archivos de pantalla, por ejemplo la tecla de función F3 se puede asociar con el
indicador 03, de tal forma que cuando el usuario pulse F3 el indicador 03 pasara a un
estado de ENCENDIDO y este estado se usara en un programa para tomar una decisión.
A nivel de archivo de pantalla se puede declarar una palabra clave que permite usar una
estructura de datos de 99 bytes para organizar los 99 indicadores en posiciones relativas
y permite referirse a ellos por un nombre significativo en lugar de usar un número.
La creación de un Subfile debe contener dos formatos de pantalla, uno describe los
campos de la lista a desplegar y el otro controla el comportamiento de la lista.
Para identificar el formato de pantalla tipo Subfile se usa la palabra clave SFL (Subfile),
también se definen los campos (columnas) a desplegar, se debe definir un campo (que
generalmente no es visible) para retener el valor llave de los registros que se despliegan
y usarlo para recuperar un registro que el usuario seleccione para una operación
adicional (Consulta, actualización etc.).
El formato de control debe definirse inmediatamente después del formato de la lista del
Subfile. Este registro controla el despliegue de los registros de la lista del Subfile a
través de palabras clave a nivel de registro, además se usa para incluir encabezados e
información adicional al usuario.
PALABRAS RESERVADAS PARA CONTROLAR SUBFILES
OVERLAY: Esta palabra sirve para poder desplegar otros formatos de pantalla
adicionales a la lista Subfile y el Formato de Control para dar más información al
usuario, por ejemplo el uso de las teclas de función.
PAGEDOWN: También se asocia con un indicador que sirve para detectar si el usuario
presionó la tecla de paginación (Page Down).
Lenguaje RPG ILE para AS/400 - IBMi en formato Free usando sentencias SQL
para manipular las tablas de la Base de Datos
En este entorno, los programas de llamada y los programas llamados se puede decir que
son Programas completos en sí mismos, habiendo sido compilados individualmente.
Esta técnica se denomina llamada de programa dinámica. Con esta técnica, cuando
un programa hace un llamado a otros programas, el sistema busca el programa llamado
de forma dinámica, durante el tiempo de ejecución, utilizando un proceso interno
conocido como resolución. El programa que realiza la llamada depende de la existencia
del programa llamado, no hay dependencia en el momento de compilación, sino en el
momento de ejecución. Los programas nunca están conectados físicamente, pero pueden
ejecutarse entre sí en tiempo de ejecución.
Introducción a Procedimientos
Los procedimientos se pueden crear independientemente del resto de los programas que
los procesarán. Se pueden codificar en miembros fuente separados y compilarlos en
módulos separados, para luego vincularlos cuando se cree un programa.
Los procedimientos introducen el concepto de variables locales en RPG. Las variables
locales se reconocen solo dentro del procedimiento en el que están definidas. Los
valores de datos se comunican de un procedimiento a otro a través de parámetros.
Los conceptos de diseño modular también fomentan la división del trabajo entre varios
programadores en un equipo, lo que permite que cada uno trabaje en partes separadas
del mismo programa para hacer el mejor uso de los recursos.
En las lecciones anteriores, todos los programas que hemos presentado y discutido
contienen, un procedimiento principal. El procedimiento principal es el primer punto de
entrada que se ejecuta cuando se inicia el programa; y es el controlador de la ejecución
del programa, este concepto es importante tenerlo presente para los cambios que vamos
a presentar en donde hacemos uso del enlace estático.
Módulos NOMAIN
La arquitectura ILE permite codificar una miembro fuente que consta de un segmento
de código sin un procedimiento principal. El módulo Nomain resultante contiene solo
procedimientos o métodos (uno o más) que se pueden combinar con otros módulos para
crear un programa. Por sí mismo, un módulo Nomain no puede crear un objeto de
programa. Uno de los módulos de un programa debe tener un procedimiento
principal, es decir con un punto de entrada.
Un módulo Nomain debe incluir una instrucción Ctl-opt con la palabra clave Nomain en
la sección de opciones de control.
Ejemplo:
End-proc MODVAL_SQL;
Al igual que con los programas que hemos visto hasta ahora, los procedimientos
también requieren prototipos e interfaces para establecer la comunicación.
Ejemplo:
ctl-opt Nomain ;
/COPY EGO1L1/QSOURCES,PROTOTYPES
Dcl-pi MODVAL_SQL;
End-pi;
.
End-proc MODVAL_SQL;
Los módulos Nomain permiten al programador ILE RPG aprovechar al máximo los
conceptos de programación modular. El código que es común a muchos programas
puede aislarse como un procedimiento en un módulo Nomain y luego reutilizarse
muchas veces por cualquier programa que lo necesite. Además, los módulos Nomain
pueden eliminar el código redundante en una aplicación, haciendo que la aplicación sea
más fácil de mantener y más confiable en comparación de si la aplicación tuviera
múltiples copias del mismo código dispersas entre muchos programas.
Los módulos Nomain también pueden ayudar a las empresas para centralizar las
funciones de la aplicación en una biblioteca común de módulos para su uso y
reutilización en toda la organización.
CRTPGM (Create Program) => Creación de un programa ejecutable que se enlaza con
módulos
Un directorio de enlace es un objeto (tipo *Bnddir) que contiene una lista de los
módulos que el comando CRTPGM puede necesitar para crear un programa ILE. El
comando de enlace CRTPGM puede hacer referencia a uno o más directorios de enlace
para encontrar el código necesario para completar el proceso de enlace.
Para utilizar el directorio de enlace al crear un programa, debe declararlo cuando ingrese
el comando CRTPGM.
Esta seria la forma de crear un programa para que incluya métodos de un directorio de
enlace:
CRTPGM PGM(nombre-programa) +
BNDDIR(nombre-binder)
Para pasar un parámetro por valor, se codifica la palabra clave Value en la interfaz y en
el prototipo del procedimiento.
Ejemplo:
Dcl-pi MODVAL_SQL;
End-pi;
Programas de servicio
Cuando se hace un enlace con un programa de servicio, el proceso no copia código a los
programas cliente, lo que hace el proceso es asociar una referencia entre el programa
cliente y el programa de servicio que incluye a todos los procedimientos que están
contenidos en él.
El programa de servicio tiene solo una firma actual, pero puede conservar muchas
firmas anteriores, que representan muchas interfaces públicas diferentes. Cuando se
vincula un programa de servicio a un programa cliente, el proceso de enlace asocia los
dos objetos utilizando la firma actual. Pero si existen programas cliente que identifican
el programa de servicio por una firma previa, esos programas pueden continuar usando
el programa de servicio sin volver a compilar o volver a enlazar. El comando
DSPSRVPGM muestra todas sus firmas válidas.
El lenguaje Binder es una sintaxis especial que consta de comandos para describir la
interfaz externa de un programa de servicio. Usando un editor, se ingresan comandos en
un miembro fuente (tipo BND) y luego se refiere a ese miembro fuente cuando se crea
el programa de servicio. Aunque no se compila el miembro fuente, se usa en un
algoritmo que se utiliza para crear la firma del programa de servicio. Hay tres comandos
del lenguaje Binder:
STRPGMEXP (Inicio de la lista de módulos que podrán ser usados por programas
cliente)
STRPGMEXP PGMLVL(*CURRENT)
EXPORT SYMBOL("MODVAL_SQL")
ENDPGMEXP
La declaración STRPGMEXP inicia el comienzo del lenguaje Binder para definir una
firma para el programa de servicio. La especificación PGMLVL (*CURRENT)
corresponde al valor de la firma actual. La declaración ENDPGMEXP indica el final de
la firma. Entre las declaraciones inicial y final, las declaraciones EXPORT enumeran
los procedimientos que estarán incluidos en la firma.
CRTSRVPGM SRVPGM(APPSRVPGM) +
MODULE(MODVAL_SQL) +
EXPORT(*SRCFILE) +
SRCFILE(QSOURCES) +
SRCMBR(APPSRVPGM)
Una vez creado el programa de servicio, se puede ver la firma resultante mediante el
comando DSPSRVPGM (Mostrar programa de servicio). La firma es un string de 16
caracteres generada por el sistema. Cuando se vincula el programa de servicio a un
programa cliente, el cliente también almacena la firma actual del programa de servicio.
STRPGMEXP PGMLVL(*CURRENT)
EXPORT SYMBOL("MODVAL_SQL")
EXPORT SYMBOL("MODINC_SQL")
ENDPGMEXP
STRPGMEXP PGMLVL(*PRV)
EXPORT SYMBOL("MODVAL_SQL")
ENDPGMEXP
Grupos de activación
Los programas ILE RPG (RPG IV), admiten todas las características ILE modernas.
Aunque los programas ILE RPG pueden ejecutarse en el grupo de activación
predeterminado DFTACTGRP(*YES), no deberían. Si se ejecutan en el grupo de
activación predeterminado DFTACTGRP(*YES), no se admitirá módulos,
procedimientos o programas de servicio, entre otras restricciones.
El grupo de activación por defecto es el que usaban los programas RPG antes de que se
creara la arquitectura ILE.
Hay varias opciones para seleccionar un grupo de activación:
La opción de grupo de activación más útil puede ser la opción *CALLER. Esta opción
no especifica ningún grupo de activación en particular. Con esta opción, el programa
simplemente se ejecuta en el mismo grupo de activación que el programa que lo llamó.
No se crea ningún grupo de activación nuevo; en cambio, el programa usa los mismos
recursos que el programa llamante.