Blogia
MeSeminary

Excepciones

Las excepciones en el sistema gestor Oracle y el lenguaje PL/SQL, nos ayudan a detectar y tratar errores en tiempo de ejecución.
Atención: Contenido exclusivo de DesarrolloWeb.com. No reproducir. Copyright.
En este artículo del Manual de PL/SQL de Oracle vamos a ver lo que son las excepciones, para qué sirven y cómo utilizarlas. Daremos un repaso también a los tipos de excepciones, las excepciones definidas por el usuario y la sintaxis con la que tenemos que especificarlas.

Por último, de paso que vemos cosas acerca del tratamiento de errores en PL/SQL, explicaremos el RAISE_APPLICATION_ERROR, un componente del sistema gestor de base de datos Oracle que ayuda a gestionar errores y sus mensajes de error.

Qué son las excepciones en Oracle

Las excepciones, presentes en la mayoría de los lenguajes de programación, sirven para tratar errores en tiempo de ejecución. En el sistema que nos ocupa, Oracle, sirven también para definir qué se debe hacer frente a errores en sentencias definidas por el usuario. Cuando se produce un error PL/SQL levanta una excepción y pasa el control a la sección excepción correspondiente al bloque PL/SQL.

El formato sería el siguiente:

BEGIN
   .........
   ......
   ......
EXCEPTION
   WHEN <nombre_excepción> THEN
      <instrucciones>;
   ......
   [WHEN OTHERS THEN <instrucciones>;]
END;

Excepciones predefinidas

Son aquellas que se disparan automáticamente al producirse determinados errores. Estas son las más comunes:

too_many_rows: Se produce cuando select … into devuelve más de una fila. 
no_data_found: se produce cuando un select …. into no devuelve ninguna fila. 
login_denied: error cuando intentamos conectarnos a Oracle con un login y clave no validos. 
not_logged_on: se produce cuando intentamos acceder a la base de datos sin estar conectados. 
program_error: se produce cuando hay un problema interno en la ejecución del programa. 
value_error: se produce cuando hay un error aritmético o de conversión. 
zero_divide: se puede cuando hay una división entre 0. 
dupval_on_index: se crea cuando se intenta almacenar un valor que crearía duplicados en la clave primaria o en una columna con restricción UNIQUE. 
invalid_number: se produce cuando se intenta convertir una cadena a un valor numérico.

Hay alguna más pero estas son las más utilizadas y tenemos que tener en cuenta que no es necesario declararlas en la sección DECLARE.

Excepciones definidas por el usuario

Son aquellas que crea el usuario. Para ello se requieren tres pasos: 
  1. Definición: se realiza en la zona de DECLARE con el siguiente formato: nombre_excepción EXCEPTION
  2. Disparar o levantar la excepción mediante la orden raise: RAISE ;
  3. Tratar la excepción en el apartado EXCEPTION: WHEN THEN ;

Para que esto quede más claro ponemos un ejemplo a continuación.

DECLARE
...
Importe_mal EXCEPTION;
...
BEGIN
...
IF precio NOT BETWEEN mínimo and máximo THEN
   RAISE importe_mal;
END IF;
...
EXCEPTION
   WHEN importe_mal THEN DBMS_OUTPUT.PUT_LINE("Importe incorrecto");
   ...
END;

Otras excepciones

Existen otros errores internos de Oracle que no tienen asignada una excepción, sino un código de error y un mensaje, a los que se accede mediante funciones SQLCODE y SQLERRM. Cuando se produce un error de estos se trasfiere directamente el control a la sección EXCEPTION donde se tratara el error en la clausula WHEN OTHERS de la siguiente forma:

WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Error'||SQLCODE||SQLERRM.)

Utilización de RAISE_APPLICATION_ERROR

En el paquete DBMS_STANDARD se incluye un procedimiento llamado RAISE_APPLICATION_ERROR que nos sirve para levantar errores y definir mensajes de error. Su formato es el siguiente:

RAISE_APPLICATION_ERROR(numero_error,mensaje_error);

Es importante saber que el numero de error esta comprendido entre -20000 y -20999 y el mensaje es una cadena de caracteres de hasta 512 bytes. 
Este procedimiento crea una excepción que solo puede ser tratada en WHEN OTHERS.

Ponemos un ejemplo para que nos quede más claro.

CREATE or REPLACE PROCEDURE subir_horas (emple NUMBER, horas_subir NUMBER)
IS
   horas_actuales NUMBER;
BEGIN
   Select horas into horas_actuales from empleados where id_empleado=emple;
   if horas_actuales is NULL then
      RAISE_APPLICATION_ERROR(-20010,'No tiene horas');
   else
      update empleados set horas=horas_actuales + horas_subir where id_empleado=emple;
   end if;
End subir_horas;

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
  -- Ejecucion
EXCEPTION
  -- Excepcion
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 yZERO_DIVIDE. Cualquier otra excepcion será capturada en el bloque WHEN OTHERS THEN.

 

 

DECLARE
 -- Declaraciones
BEGIN
  -- Ejecucion
EXCEPTION
WHEN NO_DATA_FOUND THEN

  -- Se ejecuta cuando ocurre una excepcion de tipo NO_DATA_FOUND
WHEN ZERO_DIVIDE THEN
  -- Se ejecuta cuando ocurre una excepcion de tipo ZERO_DIVIDE


WHEN OTHERS THEN
  -- Se ejecuta cuando ocurre una excepcion de un tipo no tratado
-- en los bloques anteriores


END;

 

    Como ya hemos dicho 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 excepcion apropiado para el tipo de excepción se ejecuta dicho bloque. Si no existe un bloque de control de excepciones adecuado al tipo de excepcion se ejecutará el bloque de excepcion WHEN OTHERS THEN (si existe!). WHEN OTHERS debe ser el último manejador de excepciones.

    Las excepciones pueden ser definidas en forma interna o explícitamente por el usuario. Ejemplos de excepciones definidas en forma interna son la división por cero y la falta de memoria en tiempo de ejecución. Estas mismas condiciones excepcionales tienen sus propio 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 

    PL/SQL proporciona un gran número de excepciones predefinidas que permiten controlar las condiciones de error más habituales.

    Las excepciones predefinidas no necesitan ser declaradas. Simplemente se utilizan cuando estas son lanzadas por algún error determinado.

    La siguiente es la lista de las excepciones predeterminadas por PL/SQL y una breve descripción de cuándo son accionadas:

 

Excepcion

Se ejecuta ...

SQLCODE

ACCESS_INTO_NULLEl programa intentó asignar valores a los atributos de un objeto no inicializado-6530
COLLECTION_IS_NULLEl programa intentó asignar valores a una tabla anidada aún no inicializada-6531
CURSOR_ALREADY_OPENEl programa intentó abrir un cursor que ya se encontraba abierto. Recuerde que un cursor de ciclo FOR automáticamente lo abre y ello no se debe especificar con la sentencia OPEN-6511
DUP_VAL_ON_INDEXEl programa intentó almacenar valores duplicados en una columna que se mantiene con restricción de integridad de un índice único (unique index)-1
INVALID_CURSOREl programa intentó efectuar una operación no válida sobre un cursor-1001
INVALID_NUMBEREn una sentencia SQL, la conversión de una cadena de caracteres hacia un número falla cuando esa cadena no representa un número válido-1722
LOGIN_DENIEDEl programa intentó conectarse a Oracle con un nombre de usuario o password inválido-1017
NO_DATA_FOUNDUna sentencia SELECT INTO no devolvió valores o el programa referenció un elemento no inicializado en una tabla indexada100
NOT_LOGGED_ONEl programa efectuó una llamada a Oracle sin estar conectado-1012
PROGRAM_ERRORPL/SQL tiene un problema interno-6501
ROWTYPE_MISMATCHLos elementos de una asignación (el valor a asignar y la variable que lo contendrá) tienen tipos incompatibles. También se presenta este error cuando un parámetro pasado a un subprograma no es del tipo esperado-6504
SELF_IS_NULLEl parámetro SELF (el primero que es pasado a un método MEMBER) es nulo-30625
STORAGE_ERRORLa memoria se terminó o está corrupta-6500
SUBSCRIPT_BEYOND_COUNTEl 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-6533
SUBSCRIPT_OUTSIDE_LIMITEl programa está referenciando un elemento de un arreglo utilizando un número fuera del rango permitido (por ejemplo, el elemento “-1”)-6532
SYS_INVALID_ROWIDLa conversión de una cadena de caracteres hacia un tipo rowid falló porque la cadena no representa un número-1410
TIMEOUT_ON_RESOURCESe excedió el tiempo máximo de espera por un recurso en Oracle-51
TOO_MANY_ROWSUna sentencia SELECT INTO devuelve más de una fila-1422
VALUE_ERROROcurrió un error aritmético, de conversión o truncamiento. Por ejemplo, sucede cuando se intenta calzar un valor muy grande dentro de una variable más pequeña-6502
ZERO_DIVIDEEl programa intentó efectuar una división por cero-1476

 

Excepciones definidas por el usuario 

    PL/SQL permite 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, asignandole 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;

 

Reglas de Alcance:

Una excepcion es válida dentro de su ambito de alcance, es decir el bloque o programa donde ha sido declarada. Las excepciones predefinidas son siempre válidas.

Como las variables, una excepción declarada en un bloque es local a ese bloque y global a todos los sub-bloques que comprende.

La 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 < 0 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.

    Recordar la existencia de la excepción OTHERS, que simboliza cualquier condición de excepción que no ha sido declarada. Se utiliza comúnmente para controlar cualquier tipo de error que no ha sido previsto. En ese caso, es común observar la sentencia ROLLBACK en el grupo de sentencias de la excepción o alguna de las funciones SQLCODE – SQLERRM, que se detallan en el próximo punto.

Uso de SQLCODE y SQLERRM

Al manejar una excepción es posible usar las funciones predefinidas SQLCode y SQLERRM para aclarar al usuario la situación de error acontecida.

SQLcode devuelve el número del error de Oracle y un 0 (cero) en caso de exito al ejecutarse una sentencia SQL.

Por otra parte, SQLERRM devuelve el correspondiente mensaje de error.

Estas funciones son muy útiles cuando se utilizan en el bloque de excepciones, para aclarar el significado de la excepción OTHERS.

Estas funciones no pueden ser utilizadas directamente en una sentencia SQL, pero sí se puede asignar su valor a alguna variable de programa y luego usar esta última en alguna sentencia.

 


DECLARE
  err_num NUMBER;

  err_msg VARCHAR2(255);
result NUMBER;
BEGIN
  SELECT 1/0 INTO result 
FROM DUAL;
 
EXCEPTION 
WHEN OTHERS THEN
 

  err_num := SQLCODE;
  err_msg := SQLERRM;
  DBMS_OUTPUT.put_line('Error:'||TO_CHAR(err_num));
  DBMS_OUTPUT.put_line(err_msg);
END;

 

También es posible entregarle a la función SQLERRM un número negativo que represente un error de Oracle y ésta devolverá el mensaje asociado.

 


DECLARE
  msg VARCHAR2(255);
BEGIN
  msg := SQLERRM(-1403);
  DBMS_OUTPUT.put_line(MSG);
END;

 

 

 

0 comentarios