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