1. Introdução
Este artigo aborda dois temas avançados e de fundamental importância no tratamento de exceções na linguagem PL/SQL:
- Exceções programadas: exceção que é disparada apenas em situações definidas pelo programador.
- Blocos internos para tratamento de exceções: recurso que adiciona maior controle ao mecanismo de tratamento de erros.
Como sugestão de leitura deixo o artigo “Tratamento de Exceções de Sistema na linguagem PL/SQL”, onde foram introduzidos os conceitos básicos sobre o tratamento de exceções na linguagem PL/SQL e apresentada a “receita” para realizar o tratamento das exceções de sistema.
2. Exceções Programadas
Caso o programador deseje, poderá definir os seus próprios tipos de exceção na linguagem PL/SQL. Neste caso - ao contrário do que ocorre com as exceções de sistema mostradas artigo citado - a exceção não será disparada automaticamente, mas apenas quando determinadas ações especificadas pelo programador ocorrerem. Para criar exceções programadas, você deve seguir dois passos:
- Criar uma variável do tipo EXCEPTION na seção de declarações de seu procedure ou função.
- Inserir um tratador para a sua exceção no bloco de exceções. O comando RAISE é usado para forçar com que a sua exceção seja disparada.
O programa da Listagem 1 exemplifica a utilização das exceções programadas. Trata-se de um procedure que imprime os n primeiros números ímpares, onde n é um parâmetro de entrada especificado pelo usuário. O procedure possui uma exceção programada que é disparada sempre que n for passado com um valor menor igual a zero.
CREATE OR REPLACE PROCEDURE p_impares(n IN NUMBER) IS /* ----------------------------------------------------------- PROCEDURE : p_impares DESCRIÇÃO : imprime os “n” primeiros números ímpares ----------------------------------------------------------- */ i PLS_INTEGER; j PLS_INTEGER := 1; e_param_invalido EXCEPTION; -- exceção definida pelo programador BEGIN -- esta linha força com que a exceção programada seja disparada -- caso n seja menor ou igual a zero IF n <= 0 THEN RAISE e_param_invalido; END IF; i:=1; FOR i IN 1..N LOOP DBMS_OUTPUT.PUT_LINE(j); j:= j + 2; END LOOP; EXCEPTION WHEN e_param_invalido THEN -- tratamento da exceção programada DBMS_OUTPUT.PUT_LINE('----------------------------------'); DBMS_OUTPUT.PUT_LINE('Erro!!!'); DBMS_OUTPUT.PUT_LINE('O parametro n deve ser >= 1.'); DBMS_OUTPUT.PUT_LINE('----------------------------------'); END p_impares; /
Para executar o programa, basta logar no SQL*Plus e chamar o procedure conforme indicado na Figura 1. Se, como é mostrado no exemplo, passarmos o valor 0 como entrada (ou um número negativo), a exceção programada irá disparar, produzindo uma mensagem de erro no console (para a mensagem aparecer, não esqueça de habilitar a saída do console com SET SERVEROUT ON).
Dentro de um programa PL/SQL você pode definir quantas exceções programadas desejar. Para disparar cada exceção basta utilizar o processo mostrado na Listagem 1.
3. Blocos Internos para Tratamento de Exceções
A linguagem PL/SQL permite que você possa embutir blocos anônimos dentro do corpo principal do seu programa. Neste caso, eles são chamados de sub-blocos ou blocos internos. Estes blocos são delimitados com o uso das palavras BEGIN e END e têm como característica mais importante o fato de poderem manter uma seção própria para o tratamento de exceções. Isto adiciona um maior grau de controle ao mecanismo de tratamento de erros. A Figura 2 mostra um exemplo de programa com dois blocos internos.
O esquema da Figura 2 mostra um programa estruturado para funcionar da seguinte forma. Quando começar a executar, entrará no BLOCO INTERNO 1. Se alguma exceção ocorrer nos comandos pertencentes a este bloco, a seção para tratamento de exceções que será executada é a do BLOCO INTERNO 1 e não a seção do corpo principal.
Após o BLOCO INTERNO 1 ser inteiramente processado, o programa passará a executar os comandos do BLOCO INTERNO 2. Isto ocorrerá independentemente do fato de ter ou não ocorrido um erro durante a execução do bloco anterior. Da mesma forma que ocorreu no processamento do BLOCO 1, se algum erro ocorrer durante o processamento do BLOCO INTERNO 2 é a sua própria seção de exceções que será usada para tratá-lo.
O programa da Listagem 2 exemplifica a utilização de blocos internos. Trata-se de um procedure que recebe dois parâmetros numéricos x e y. Inicialmente, o programa realiza a divisão de x por y dentro de um bloco delimitado por BEGIN e END (BLOCO 1). Caso y tenha valor zero, será disparada a exceção associada a este bloco (obs: é uma exceção do tipo ZERO_DIVIDE. Consulte o artigo citado no início do texto se você não ainda não conhece os tipos de exceção da PL/SQL). Em seguida, o programa realiza a divisão de y por x dentro de outro bloco (BLOCO 2). Desta vez, caso x tenha o valor zero, será disparada a exceção associada ao BLOCO 2 (mais uma vez uma exceção do tipo ZERO_DIVIDE).
CREATE OR REPLACE PROCEDURE p_duas_divisoes(x IN NUMBER, y IN NUMBER) IS /* ----------------------------------------------------------- PROCEDURE : p_duas divisões DESCRIÇÃO : calcula e imprime x/y e y/x ----------------------------------------------------------- */ resultado1 NUMBER; resultado2 NUMBER; BEGIN -- BLOCO INTERNO 1: Tratamento de x/y BEGIN resultado1 := x/y; DBMS_OUTPUT.PUT_LINE('x/y = ' || TO_CHAR(resultado1)); EXCEPTION WHEN ZERO_DIVIDE THEN -- tratamento da exceção disparada se y=0 DBMS_OUTPUT.PUT_LINE('----------------------------------'); DBMS_OUTPUT.PUT_LINE('Erro!!!'); DBMS_OUTPUT.PUT_LINE('O parametro y deve ser diferente de 0.'); DBMS_OUTPUT.PUT_LINE('----------------------------------'); END; -- BLOCO INTERNO 2: Tratamento de y/x BEGIN resultado2 := y/x; DBMS_OUTPUT.PUT_LINE('y/x = ' || TO_CHAR(resultado2)); EXCEPTION WHEN ZERO_DIVIDE THEN -- tratamento da exceção disparada se x=0 DBMS_OUTPUT.PUT_LINE('----------------------------------'); DBMS_OUTPUT.PUT_LINE('Erro!!!'); DBMS_OUTPUT.PUT_LINE('O parametro x deve ser diferente de 0.'); DBMS_OUTPUT.PUT_LINE('----------------------------------'); END; END p_duas_divisoes; /
A Figura 3 apresenta exemplos de três chamadas do programa. Na primeira chamada, passamos y com valor zero, disparando a exceção definida no BLOCO 1. Na segunda chamada, x foi passado com valor 0, fazendo com que fosse disparada a exceção associada ao BLOCO 2. Na terceira chamada, x = 1 e y = 2 e assim o programa roda normalmente, sem que nenhuma exceção seja disparada.
Assim concluímos este artigo abordando o tratamento de exceções na linguagem PL/SQL.