Saber si registro está siendo usado.
Te paso un artículo MUY interesante referente a lo que preguntas .....
Manejar errores en RPG
BIF de realimentación
Una función incorporada (BIF) de realimentación nos indica si una operación se ha ejecutado correctamente. En la Figura 1 pueden verse las BIF de realimentación más habituales utilizadas en RPG de formato libre. Todas estas BIF devuelven un valor indicador *On u *Off. Las BIF normalmente se utilizan en operaciones de E/S.
Figura 1 - BIF de realimentación más habituales
BIF Operaciones
%EOF Read, ReadE, ReadP, ReadPE
%Error Open, Close, Chain, Read, ReadE,
ReadP, ReadPE, Write, Update, Delete,
Commit, RolBk, Test
%Found Chain, Delete, SetLL, SetGT
Se puede escribir %EOF y %Found después de cualquier operación importante. Para comprobar si un registro no se ha encontrado en una operación Chain se escribiría:
chain clave archivo;
if not %found( archivo );
// Manejar condicion de "no se encuentra";
endif;
Tanto la BIF %EOF como %Found permiten utilizar un argumento opcional que define el origen de la realimentación. Si no se escribe ningún argumento, la BIF hace referencia a la última operación en que se haya especificado. Así pues, la BIF %Found siguiente hace referencia a archivo2, no a archivo1:
chain clave1 archivo1;
chain clave2 archivo2;
if not %found( );
La BIF %Error puede escribirse solamente después de una operación que especifique el expansor de error. Para verificar un error en una operación Write, escribiríamos:
write(e) format;
if %error();
// Manejar error
endif;
A diferencia de %EOF y %Found, %Error no tiene ningún argumento para definir el origen de la realimentación. La BIF %Error se escribe inmediatamente después de la operación a la que hace referencia. Verá que %Error es particularmente útil a la hora de comprobar valores válidos antes de convertir un tipo de datos a otro. El código siguiente comprueba una fecha *ISO de un campo entero antes de convertirlo en un tipo fecha:
test(de) *iso int;
if not %error()
fecha = %date( int: *iso );
endif;
Este fragmento de código impedirá un error explosivo en la BIF %Date. No obstante, las BIF de realimentación normalmente no pueden impedir los errores radiactivos. Si no se detecta un error en una operación Chain o Read significa que los campos de entrada mantendrán los valores de la última operación de E/S correcta. En vez de manejar el error, acabarán reutilizándose valores falsos.
Programación a la defensiva
La programación a la defensiva intenta evitar errores o, por lo menos, manejarlos elegantemente si ocurren. Muchas operaciones deben "protegerse" mediante código que evite errores. Esto puede parecer una tarea imponente, pero la breve lista de control de la Figura 2 abarca la mayoría de los errores potenciales. El código "guardián" frecuentemente sólo comprueba condiciones límite.
Figura 2 - Lista de control para programar a la defensiva
• Índice de matriz fuera de límites
• Posición de una subserie fuera de límites
• División por cero
• Truncamiento numérico
Para prevenir errores de índices de una matriz, puede utilizarse la BIF %Elem para verificar que el índice de la matriz hace referencia a un elemento de la matriz:
if idx >= 1 and idx <= %elem( matriz );
elem = matriz( idx );
endif;
Recuerde, por supuesto, que una comprobación de los límites de un índice no garantiza que el elemento de la matriz al que se hace referencia tenga datos válidos.
Para evitar errores de posición de una subserie, utilice la BIF %Len para comprobar que la posición inicial de la subserie es válida:
if pos >= 1 and pos <= %len( serie );
subserie = %subst( serie: pos);
endif;
Para impedir la división por cero, basta con asegurarse de que el divisor no es cero:
if y <> 0;
z = x / y;
endif;
El truncamiento numérico puede prevenirse utilizando definiciones de datos estándar para asignar el tamaño a los campos de forma uniforme:
d x s like( stdInt )
d y s like( stdInt )
y = x;
El código a la defensiva suele evitar los errores explosivos. Todos los ejemplos de este apartado acabarían en un mensaje de excepción si no estuvieran protegidos. Utilice código a la defensiva, siempre que sea posible, para prevenir errores que pueden preverse fácilmente.
Supervisión de errores Hasta ahora hemos visto cómo utilizar las BIF y la programación a la defensiva para evitar o manejar errores evidentes. Sin embargo, no todos los errores son obvios. Veamos un ejemplo sencillo:
z = (a - b) / (c - d);
Es el denominador lo que importa:
if (c - d) <> 0;
z = (a - b) / (c - d);
endif;
Pero este enfoque no es ideal puesto que la operación If sólo se ocupa de la mitad de la asignación. Esto tiene implicaciones en el rendimiento, en la legibilidad y en la facilidad de mantenimiento en el caso de ecuaciones más complejas. De todas formas, la solución anterior podría considerarse aceptable si fuera sólida. Pero no lo es. Pensemos en lo que ocurriría si (a - b) fuera un valor muy grande y (c - d) un valor muy pequeño: puede ocurrir un truncamiento. Y nuestro código a la defensiva no contempla esa posibilidad. Aquí es donde se necesita aplicar el sentido común. Si existe una remota posibilidad de que ocurra un error, entonces contrólelo y corríjalo:
monitor;
z = (a - b) / (c - d);
on-error;
z = 0;
endmon;
Este ejemplo utiliza un grupo monitor para verificar si ocurre un error. Los grupos monitor comprueban la existencia de errores en las operaciones entre la operación Monitor y la primera operación On-Error. Si ocurre un error, el control se le pasa al bloque de código On-Error pertinente. Si todas las operaciones son correctas, el control se le pasa a la operación EndMon. En este caso, el bloque monitor asigna 0 a z si ocurre un error.
Un grupo monitor puede incluir varias sentencias On-Error que verifiquen distintas condiciones de error, además de una sentencia On-Error genérica, como la del ejemplo anterior. El ejemplo siguiente supervisa explícitamente la división por cero (00102) y el truncamiento (00103):
monitor;
z = (a - b) / (c - d);
on-error 00102;
// Manejar división por cero
on-error 00103;
// Manejar truncamiento
on-error;
// Manejar otros errores
endmon;
La sentencia On-Error puede especificar múltiples condiciones de error separadas por un signo de dos puntos o utilizando las palabras reservadas siguientes:
• *Program Detecta las condiciones de excepción de programa 00100 a 00999.
• *File Detecta las condiciones de excepción de archivo 01000 a 09999.
• *All Detecta todas las condiciones de excepción, tanto de programa como de archivo.
Observe que las condiciones 00001 a 00099 no pueden supervisarse (puede consultarse la lista completa de condiciones en el Capítulo 5, "File and Program Exceptions/Errors", del manual ILE RPG Reference.
Los grupos monitor pueden anidarse. Si se produce un error dentro de grupos monitor anidados, el grupo más profundo que pueda detectar el error recibirá el control. Los grupos monitor no pueden detectar errores ejecutados en subrutinas independientes. Sin embargo, pueden detectar errores en procedimientos o programas a los que se llama que no detectan sus propios errores pero terminan con la condición 00202: Error en programa o procedimiento llamado. Si un procedimiento supervisa un error, la sentencia On-Error recibe el control. Si un procedimiento no contiene un grupo monitor, el control lo recibe la sentencia On-Error pertinente del procedimiento desde el que se llama.
Los grupos monitor anidados en el mismo procedimiento o en procedimientos anidados pueden añadir complejidad al código y la complejidad probablemente introducirá sus propios errores. Mi consejo es que simplifique. Dé por supuesto que cada procedimiento controlará su propia recuperación de errores.
Asegúrese de que la recuperación del error es completa y de que tiene el efecto buscado. Veamos el ejemplo siguiente:
monitor;
a = x;
b = y;
c = z;
on-error;
// Manejar errores
endmon;
¿Cómo debería manejar el código los errores? Puede ocurrir un error en cualquiera de las asignaciones. Supongamos que el código se ejecuta en un bucle. En la segunda iteración se produce un error en la segunda asignación. A a se le ha asignado un valor. Al asignar el valor de b se ha producido el error. C conserva el valor de la iteración anterior. Una forma de manejar un error es anularlo todo:
monitor;
a = x;
b = y;
c = z;
on-error;
a = 0;
b = 0;
c = 0;
endmon;
Este método funciona bien si a, b y c son dependientes y un error en cualquiera de los campos invalidaría los tres. En cambio, existen dos alternativas. La primera, anular todos los campos de resultados antes de asignarles un valor y utilizar el grupo monitor para detectar la excepción:
a = 0;
b = 0;
c = 0;
monitor;
a = x;
b = y;
c = z;
on-error;
// No hacer nada
endmon;
Este sistema funciona si se quieren asignar variables antes de que se produzca un error. Opcionalmente, el grupo monitor puede dividirse en tres grupos sencillos del tipo:
monitor;
a = x;
on-error;
a = 0;
endmon;
Esta técnica funciona si se quieren realizar las tres asignaciones, independientemente de que se produzcan o no errores. Incluso con un simple bloque de código, hay muchas formas de manejar errores. La estrategia adecuada es la que mejor refleje el propósito del código, pero sea la que sea, asegúrese de que el manejo de errores detecte los errores y se recupere de ellos cuando corresponda. Sobre todo, no oculte los errores:
monitor;
a = x;
on-error;
// No hacer nada
endmon;
Este código empeora las cosas al convertir un error explosivo en uno radiactivo.
Todos los ejemplos de errores de asignación que hemos visto acaban recuperándose asignando un valor por omisión (0). Siempre que sea posible, lo mejor es utilizar un tipo de recuperación de errores que permita que la aplicación siga ejecutándose. Pero, en algunos casos, los errores son tan graves que es necesario someterlos a examen. Eso no significa que el programa tenga que detenerse. Con frecuencia es suficiente con mostrar el error en pantalla, en un informe o en un archivo de registro y, a continuación, recuperarse y continuar con la ejecución.
Cuando se sigue este método, hay que capturar los detalles del error. En el caso de los errores de programa, puede encontrar los detalles en la estructura de datos de estado de programa. Si se trata de errores de E/S, encontrará los detalles en la estructura de datos de información de archivo. Ambas estructuras de datos incluyen subcampos que definen la condición de error, el ID de mensaje correspondiente y otros datos relevantes. Para capturar el error, en la operación On-Error hay que utilizar las palabras reservadas *Program y *File:
monitor;
// Hacer algo
on-error *program;
status = program.status;
on-error *file;
status = fileInfo.status;
endmon;
Hallará más información acerca de las estructuras de datos de información de programa y de archivo en el capítulo 5 de la publicación RPG Reference.
Procedimientos de finalización
Los programas finalizan de forma anómala por muchas razones: un error no verificado puede provocar una excepción; una sesión interactiva puede finalizar anormalmente; un usuario puede cancelar un programa con la opción 2 de Petición de sistema; un usuario puede interrumpir un trabajo; etcétera. ILE ofrece un medio uniforme de manejar todas las formas de finalización anómala. La API CEETRX registra un procedimiento de salida de usuario de finalización de entrada de pila de llamadas (procedimiento de finalización, para abreviar) que se ejecuta cuando la entrada de la pila de llamada finaliza sin devolver un valor a quien ha realizado la llamada. Un procedimiento de finalización permite salir de forma controlada después de una finalización anómala.
El programa ExitProc (Figura 5, incluida en la versión impresa de la revista) ejemplifica cómo utilizar un procedimiento de finalización. Llame al programa con el parámetro "1" para generar una excepción o llámelo con un parámetro "2" y luego seleccione la opción 2 de Petición de sistema para cancelar el programa. En ambos casos, recibirá el mensaje "CleanUp ran" que indica que el procedimiento de finalización se ha ejecutado al acabar el programa.
El programa ExitProc define el prototipo del procedimiento cleanUp que actuará como procedimiento de finalización. El prototipo setExitProcedure define los parámetros de la API CEETRX, que se llama para registrar el procedimiento cleanUp. El sistema llamará al procedimiento cleanUp si el programa finaliza de forma anómala.
Un procedimiento de finalización puede incluir el código que se quiera. El truco está en ser breve y conciso: no se arriesgue a escribir demasiado código, que podría provocar una excepción en el procedimiento de finalización. Lo nor mal es que quiera cerrar archivos, eliminar objetos temporales como por ejemplo espacios de usuario, o enviar un trabajo para que procese un lote de datos. Generalmente es buena idea proteger el código del procedimiento de finalización en bloques monitor. Si quiere obtener más información acerca de los procedimientos de finalización, consulte el apartado "Activation Groups and Control Flow APIs" .
Su turno
El RPG permite muchas formas de manejar errores. En concreto, las BIF de realimentación, las técnicas de programación a la defensiva, la supervisión de errores y los procedimientos de finalización son una base firme para controlar errores. La forma de utilizar esa base está en sus manos y depende de la estructura y propósito del código. El manejo de errores debe ser sencillo. Utilice métodos estándar para reforzar la arquitectura de la aplicación. Procure detectar los errores lo antes posible. Haga de la prevención una prioridad utilizando las BIF de realimentación y el código a la defensiva. Cuando la prevención falle, utilice la supervisión del código como base para la recuperación. Como último recurso, los procedimientos de finalización proporcionan un método de salir de forma controlada después de una anomalía.