Para melhor visualização, recomendo resolução de no mínimo 1280 x 800 e navegador Mozilla Firefox


sexta-feira, 3 de maio de 2013

Desvendando o erro ORA-06553: PLS-382: a expressão é do tipo incorreto

Por Eduardo Legatti

Olá,

Sabemos que na linguagem SQL não existe o tipo de dado Boolean. Bom, pelo menos no que se refere ao Oracle, o tipo de dado Boolean existe apenas dentro do PL/SQL. O motivo para eu estar escrevendo este artigo vem de um cenário na qual um desenvolvedor pediu um suporte para a equipe de analistas de banco de dados na qual atuo de forma a ajudá-lo a desvendar o erro "ORA-06553: PLS-382: a expressão é do tipo incorreto" que insistia em acontecer a todo momento em que ele chamava uma função no banco de dados através de uma consulta SQL. É aí que o tipo de dado Boolean entra na estória. Para simular a situação ocorrida, tenha como exemplo a função FC_IS_WEEKEND criada abaixo:

Conectado a:
Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production
With the Partitioning, OLAP, Data Mining and Real Application Testing options

SQL> create or replace function fc_is_weekend (p_date date)
  2     return boolean
  3  as
  4     aux varchar2(3);
  5  begin
  6     select to_char (p_date,'DY','nls_date_language=AMERICAN') into aux from dual;
  7     if aux in ('SAT','SUN')
  8     then
  9        return TRUE;
 10     else
 11        return FALSE;
 12     end if;
 13  end;
 14  /

Função criada.
 
Vejamos o que acontece quando chamamos a função através de uma consulta SQL conforme demonstrado abaixo:

SQL> select fc_is_weekend(sysdate) from dual;
select fc_is_weekend(sysdate) from dual
       *
ERRO na linha 1:
ORA-06552: PL/SQL: Statement ignored
ORA-06553: PLS-382: a expressão é do tipo incorreto

Perceberam o problema? A função foi criada tendo como propósito retornar um valor Booleano (TRUE/FALSE), ou seja, se uma data passada como parâmetro cair em um final de semana, então a função deverá retornar TRUE, senão a mesma deverá retornar FALSE. O erro "ORA-06553: PLS-382" ocorre exatamente pelo fato do SQL não entender o tipo de dado Booleano que está sendo retornado pela função. Neste caso, a função somente poderá ser usada apenas dentro de um bloco PL/SQL como demonstrado abaixo:

SQL> set serveroutput on
SQL> declare
  2    aux boolean;
  3  begin
  4    aux := fc_is_weekend (sysdate);
  5    dbms_output.put_line(sys.diutil.bool_to_int(aux));
  6  end;
  7  /
0

Procedimento PL/SQL concluído com sucesso. 

Acima, eu chamei a função FC_IS_WEEKEND de dentro de um bloco PL/SQL e, para fins de demonstração, transformei o resultado para o tipo de dado numérico usando a função SYS.DIUTIL.BOOL_TO_INT de forma que o resultado pudesse ter sido mostrado. Neste caso, 0 (zero) significa FALSE. Enfim, uma forma de resolver este problema seria alterar a função existente, ou criar uma nova função conforme demonstrado a seguir:

SQL> create or replace function fc_is_weekend2 (p_date date)
  2     return number
  3  as
  4     aux boolean;
  5  begin
  6     aux := fc_is_weekend(p_date);
  7     if aux = TRUE
  8     then
  9        return 1;
 10     else
 11        return 0;
 12     end if;
 13  end;
 14  /

Função criada.

SQL> select fc_is_weekend2(sysdate) from dual;

FC_IS_WEEKEND2(SYSDATE)
-----------------------
                      0

No mais, o ideal seria que o Oracle além de entender um overload da função dentro de uma package, na qual os parâmetros de entrada das funções seriam do mesmo tipo, mas o tipo de dados de saída seriam diferentes, fosse também capaz de perceber a origem da chamada de uma função (SQL ou PL/SQL) de forma a fazer a chamada para a função correta como demonstrado abaixo. A questão é que eu não saberia dizer realmente se existiria alguma vantagem nisso.

SQL> create or replace package pkg_teste
  2  as
  3     function fc_is_weekend (p_date date) return boolean;
  4     function fc_is_weekend (p_date date) return number;
  5  end;
  6  /

Pacote criado.

SQL> create or replace package body pkg_teste
  2     as
  3        function fc_is_weekend (p_date date) return boolean as
  4         aux varchar2(3);
  5        begin
  6         select to_char (p_date,'DY','nls_date_language=AMERICAN') into aux from dual;
  7         if aux in ('SAT','SUN')
  8         then
  9            return TRUE;
 10         else
 11            return FALSE;
 12         end if;
 13        end;
 14
 15        function fc_is_weekend (p_date date) return number as
 16         aux varchar2(3);
 17        begin
 18         select to_char (p_date,'DY','nls_date_language=AMERICAN') into aux from dual;
 19         if aux in ('SAT','SUN')
 20         then
 21            return 1;
 22         else
 23            return 0;
 24         end if;
 25        end;
 26  end;
 27  /

Corpo de Pacote criado.

SQL> select pkg_teste.fc_is_weekend(sysdate) from dual;
select pkg_teste.fc_is_weekend(sysdate) from dual
       *
ERRO na linha 1:
ORA-06553: PLS-307: muitas declarações de 'FC_IS_WEEKEND' são compatíveis com esta chamada 
 



2 comentários:

Rjg disse...

Excelentes posts!!
parabéns pelo Blog

Eduardo Legatti disse...

Olá Ronei,

Obrigado pela visita!

Abraços e até mais...

Legatti

Postagens populares