Oracle
 sql >> Base de Dados >  >> RDS >> Oracle

ON CONVERSION ERROR falha com ORA-43918:Este argumento deve ser um literal

CURSOR_SHARING


O ON CONVERSION ERROR recurso não funciona quando o parâmetro CURSOR_SHARING é definido como FORCE. Para evitar esse erro, altere o parâmetro no nível do sistema, sessão ou instrução.

Idealmente, CURSOR_SHARING deve ser definido como EXACT para todo o sistema. Mas se tivermos um aplicativo que não usa variáveis ​​de ligação, provavelmente não podemos executar alter system set cursor_sharing=exact; .

O parâmetro pode ser definido no nível da sessão com alter session set cursor_sharing=exact; , mas nem sempre é conveniente alterar constantemente os parâmetros da sessão.

O parâmetro pode ser alterado no nível da instrução com a dica CURSOR_SHARING_EXACT :
SQL> select /*+ cursor_sharing_exact */ to_date(the_date default null on conversion error, 'MM/DD/YYYY') the_date
  2  from
  3  (
  4      select '1/1/2021' the_date from dual union all
  5      select 'bad date' the_date from dual
  6  );

THE_DATE
---------
01-JAN-21

Bug do analisador/otimizador


Como @gouessej descobriu, há outro motivo potencial para o erro ORA-43918 que não está relacionado ao compartilhamento de cursor. Parece haver erros de análise ou otimização relacionados à transformação de CASE e TO_ funções em algumas versões do Oracle.

Por exemplo, a instrução SQL abaixo falha no Oracle 18c e 19c:
SQL> select case when v_num is null then 0 else v_num end
  2  from
  3  (
  4      select to_number('120.3' default null on conversion error, '99999D99') as v_num
  5      from dual
  6  );
    select to_number('120.3' default null on conversion error, '99999D99') as v_num
                                                               *
ERROR at line 4:
ORA-43918: This argument must be a literal

Acredito que este seja um bug de análise ou otimizador porque o erro desaparece se você interromper as transformações adicionando um predicado como rownum >= 1 . (Quando o Oracle vê ROWNUM , ele assume que os resultados devem ser exibidos em uma determinada ordem e não aplicarão tantas transformações a esse bloco de consulta.)
SQL> select case when v_num is null then 0 else v_num end
  2  from
  3  (
  4      select to_number('120.3' default null on conversion error, '99999D99') as v_num
  5      from dual
  6  where rownum >= 1
  7  );

CASEWHENV_NUMISNULLTHEN0ELSEV_NUMEND
------------------------------------
                               120.3