EXCEPCIONES EN PL/SQL
MANEJO DE EXCEPCIONES
En PL/SQL una advertencia o condición de error es llamada una excepción. Las excepciones se controlan dentro de su propio bloque. La estructura de bloque de una excepción se muestra a continuación.
DECLARE
-- Declaraciones
BEGIN
-- Ejecución
EXCEPTION
-- Excepción
END;
Cuando ocurre un error, se ejecuta la porción del programa marcada por el bloque EXCEPTION, transfiriéndose el control a ese bloque de sentencias.
El siguiente ejemplo muestra un bloque de excepciones que captura las excepciones NO_DATA_FOUND y ZERO_DIVIDE. Cualquier otra excepción será capturada en el bloque WHEN OTHERS THEN.
DECLARE
-- Declaraciones
BEGIN
-- Ejecución
EXCEPTION
WHEN NO_DATA_FOUND THEN
-- Se ejecuta cuando ocurre una excepción de tipo NO_DATA_FOUND
WHEN ZERO_DIVIDE THEN
-- Se ejecuta cuando ocurre una excepción de tipo ZERO_DIVIDE
WHEN OTHERS THEN
-- Se ejecuta cuando ocurre una excepción de un tipo no tratado
-- en los bloques anteriores
END;
Cuando ocurre un error, se ejecuta el bloque EXCEPTION, transfiriéndose el control a las sentencias del bloque. una vez finalizada la ejecución del bloque de EXCEPTION no se continua ejecutando el bloque anterior.
Si existe un bloque de excepciones apropiado para el tipo de excepción se ejecuta dicho bloque. Si no existe un bloque de control de excepciones adecuado al tipo de excepción se ejecutara el bloque de excepción WHEN OTHERS THEN (si existe). WHEN OTHERS debe ser el último manejador de excepciones.
Las excepciones pueden ser definidas de manera interna o explícitamente por el usuario. Ejemplos de excepciones definidas de forma interna son la división por cero y la falta de memoria en tiempo de ejecución. Estas mismas condiciones excepcionales tienen tiene sus propios tipos y pueden ser referenciadas por ellos: ZERO_DIVIDE y STORAGE_ERROR
Las excepciones definidas por el usuario deben ser alcanzadas explícitamente utilizando la sentencia RAISE.
Con las excepciones se pueden manejar los errores cómodamente sin necesidad de mantener múltiples chequeos por cada sentencia escrita. También provee claridad en el código ya que permite mantener las rutinas correspondientes al tratamiento de los errores de forma separada de la lógica del negocio.
EXCEPCIONES PREDEFINIDAS
No necesitan ser declaradas. Simplemente se utilizan cuando estas son lanzadas por algún error determinado
DUP_VAL_ON_INDEX: Se produce cuando se intenta almacenar un valor ya existente en una columna que tiene restricción de índice único.
TIMEOUT_ON_RESOURCE: Se excedió el tiempo máximo de espera por un recurso en Oracle.
NOT_LOGGED_ON: El programa efectuó una llamada a Oracle sin estar conectado.
LOGIN_DENIED: El login o la contraseña utilizados para entrar en Oracle son inválidos.
NO_DATA_FOUND: Una sentencia SELECT INTO no devolvió ningún registro.
TOO_MANY_ROWS: Una sentencia SELECT INTO devolvió más de un registro.
ZERO_DIVIDE: Se ha ejecutado una división donde el divisor valía cero.
STORAGE_ERROR: Si no se dispone de más memoria o la memoria esta dañada.
PROGRAM_ERROR: Ocurrió un problema interno al ejecutar el código PL/SQL.
INVALID_NUMBER: Cuando falla la conversión de una cadena de caracteres hacia un número porque la cadena no representa un número válido.
VALUE_ERROR: Ocurrió un error aritmético, de conversión o truncamiento. Por ejemplo, esto sucede cuando se intenta dar un valor muy grande a una variable que no soporta dicho tamaño.
ROWTYPE_MISMATCH: Los elementos de una asignación (el valor a asignar y la variable que lo contendrá) son de tipos incompatibles. También se presenta este error cuando un parámetro pasado a un subprograma no es del tipo esperado.
SYS_INVALID_ROWID: Falla la conversión de una cadena de caracteres hacia un tipo rowid porque la cadena no representa un número.
INVALID_CURSOR: Se efectuó una operación no válida sobre un cursor. Suele ocurrir cuando un cursor no está abierto y se ejecuta una sentencia para cerrar dicho cursor.
CURSOR_ALREADY_OPEN: Cuando se intenta abrir un cursor que ya estaba abierto. Hay que recordar que un cursor de tipo FOR se abre automáticamente por lo que no se debe ejecutar la sentencia OPEN.
ACCESS_INTO_NULL: Se intentó asignar un valor a los atributos de un objeto no inicializado.
COLLECTION_IS_NULL: Se intentó asignar un valor a una tabla anidada aún no inicializada.
SELF_IS_NULL: El parámetro SELF (el primero que es pasado a un método MEMBER) es nulo.
SUBSCRIPT_BEYOND_COUNT: El programa está tratando de referenciar un elemento de un arreglo indexado que se encuentra en una posición más grande que el número real de elementos de la colección
SUBSCRIPT_OUTSIDE_LIMIT: El programa está referenciando un elemento de un arreglo utilizando un número fuera del rango permitido (por ejemplo, el elemento “-1”)
OTHERS: Cualquier otro tipo de error que pueda producirse. Cuando se utiliza la excepción OTHERS, cualquier excepción que no se haya tratado anteriormente se procesará según la secuencia de instrucciones incluida dentro de la sección OTHERS. OTHERS debe ser la última excepción tratada dentro de la sección dedicada al tratamiento de excepciones.
EXCEPCIONES DEFINIDAS POR EL USUARIO
Son las que permiten al usuario definir sus propias excepciones, las que deberán ser declaradas y lanzadas explícitamente utilizando la sentencia RAISE.
Las excepciones deben ser declaradas en el segmento DECLARE de un bloque, subprograma o paquete. Se declara una excepción como cualquier otra variable, asignándole el tipo EXCEPTION. Las mismas reglas de alcance aplican tanto sobre variables como sobre las excepciones.
DECLARE
-- Declaraciones
MyExcepcion EXCEPTION;
BEGIN
-- Ejecucion
EXCEPTION
-- Excepcion
END;
SENTENCIA RAISE
La sentencia RAISE permite lanzar una excepción en forma explícita. Es posible utilizar esta sentencia en cualquier lugar que se encuentre dentro del alcance de la excepción.
DECLARE
-- Declaramos una excepcion identificada por VALOR_NEGATIVO
VALOR_NEGATIVO EXCEPTION;
valor NUMBER;
BEGIN
-- Ejecucion
valor := -1;
IF valor <> THEN
RAISE VALOR_NEGATIVO;
END IF;
EXCEPTION
-- Excepcion
WHEN VALOR_NEGATIVO THEN
dbms_output.put_line('El valor no puede ser negativo');
END;
Con la sentencia RAISE podemos lanzar una excepción definida por el usuario o predefinida, siendo el comportamiento habitual lanzar excepciones definidas por el usuario.