Manipulação de erros em PL/pgSQL

 

Olá pessoal,

 

nesse artigo vamos tratar da manipulação de erros em um procedimento armazenado escrito na linguagem PL/pgSQL.

 

Por padrão, qualquer erro ocorrido em uma função PL/pgSQL aborta sua execução, e consequentemente a transação. Podemos capturar e tratar esses erros usando um bloco com uma cláusula de exceção. Sua sintaxe é uma extensão da sintaxe de um bloco comum.

 

Sintaxe:


14-11-2007pic01.JPG
 

Uma condição de erro só é executada quando acontece o tal erro (óbvio), ou seja, se não ocorrer nenhum erro durante a execução do bloco normal, todos os comandos são executados normalmente até o END final. Mas se um erro acontece durante a execução, a execução normal do bloco onde houve o erro é abandonada e o controle passa para o bloco de EXCEPTION. Se o erro ocorrido está explícito no bloco então o código correspondente é executado, senão passa para o código de tratamento de erro genérico, caso exista.

 

Em http://www.postgresql.org/docs/8.2/interactive/errcodes-appendix.html é possível verificar a lista dos possíveis erros a serem tratados.

 

Geralmente as exceptions ocorrem de duas formas:

 

Quando acontece um erro do PostgreSql a exception associada é sinalizada automaticamente. Erro gerado pelo PostgreSQL.

 

ou

 

Uma exception é explicitamente sinalizada através do comando RAISE dentro do bloco PL/pgSQL. Erro gerado intencionalmente pelo usuário.

 

Vejamos os exemplos abaixo.

 

Quando tentamos escrever um valor igual a um outro valor já existente em uma coluna de uma tabela e essa coluna é chave primária, o PostgreSQL gera um erro de chave duplicada. Esse é um erro interno gerado automaticamente pelo PostgreSQL.

 

Agora imagine que eu tenho uma função que recebe um valor inteiro como parâmetro e que esse parâmetro não pode receber um valor superior a 1000. Nesse caso, eu poderia gerar um erro através do comando RAISE, todas as vezes que alguém chamasse essa função passando um valor superior a 1000.

 

Quando um erro acontece, somente a transação do bloco onde houve o erro é interrompida. Veja o exemplo abaixo.

 

Em um banco de dados que contém uma tabela usuario com cod (integer) e nome (varchar).

 

Create function teste_except() returns integer

As $$

         Declare

                   x integer;

                   y integer;

         Begin

                   INSERT INTO usuario values (1, 'Hesley Py');

                  

                   BEGIN

                            UPDATE usuario SET nome = 'Hesley' WHERE cod = 1;

                            x := 1;

                            y := x / 0;

                   EXCEPTION WHEN division_by_zero THEN

                            RAISE NOTICE ''Capturei divisao por zero'';

                            RETURN x;

                   END;

                   return x;

         End;

$$ Language 'plpgsql';       

 

Após a execução do código acima digite:

 

         Select teste_except();

 

Neste exemplo estamos causando, propositadamente, um erro de divisão por 0. Ao final da execução você perceberá que o insert será executado corretamente, mas o update não. Isso acontece pq a transação só é interrompida (ROLLBACK) dentro do bloco onde aconteceu o erro. No exemplo mostrado o erro acontece somente no bloco (Begin ... End) onde ocorre o update.

 

A instrução RAISE é utilizada para gerar mensagens informativas e causar erros.

 

Sintaxe:

 

         RAISE nível 'formato' [, variável [, ...]];

 

Os níveis possíveis são DEBUG, LOG, INFO, NOTICE, WARNING, e EXCEPTION.

 

O nível EXCEPTION (como visto acima) causa um erro e interrompe a transação corrente; os outros níveis apenas geram mensagens com diferentes níveis de prioridade.

 

Dentro da cadeia de caracteres de formatação, o caractere % é substituído pelo valor, na forma de cadeia de caracteres, da variável.

 

Exemplo:

 

         RAISE NOTICE ''O valor da variável é %'', variavel;

 

No exemplo, o símbolo % será substituído pelo valor presente em variavel.

 

Outro exemplo, agora interrompendo a transação com a mensagem de erro fornecida:

 

         RAISE EXCEPTION ''ID inexistente --> %'', id_usuario;

 

Usando a mesma tabela usuario descrita acima. Um exemplo bem simples, imagine que o usuário com código = 1 nunca pode ser removido.

 

Create function exclui_usuario(id integer) returns void

As $$

         Begin

                   If id != 1 then

                            DELETE FROM usuario WHERE cod = id;

                   Else

                            RAISE EXCEPTION 'O usuário código % não pode ser removido', id;

                   End if;

         End;

$$ Language 'plpgsql';

 

Ao chamar essa função a partir de uma outra, a função chamadora deve possuir uma cláusula exception para tratar esse possível erro.

 

Espero que seja útil.

 

[]’s e até a próxima se Deus quiser.

 

Hesley Py