Oracle
 sql >> Database >  >> RDS >> Oracle

ON CONVERSION ERROR non riesce con ORA-43918:questo argomento deve essere un valore letterale

CURSOR_CONDIVISIONE

Il ON CONVERSION ERROR la funzione non funziona quando il parametro CURSOR_SHARING è impostato su FORCE. Per evitare questo errore, modificare il parametro a livello di sistema, sessione o istruzione.

Idealmente, CURSOR_SHARING dovrebbe essere impostato su EXACT per l'intero sistema. Ma se abbiamo un'applicazione che non usa le variabili bind, probabilmente non possiamo eseguire alter system set cursor_sharing=exact; .

Il parametro può essere impostato a livello di sessione con alter session set cursor_sharing=exact; , ma non è sempre conveniente modificare costantemente i parametri di sessione.

Il parametro può essere modificato a livello di istruzione con l'hint 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 del parser/ottimizzatore

Come scoperto da @gouessej, esiste un altro potenziale motivo per l'errore ORA-43918 che non è correlato alla condivisione del cursore. Sembra che ci siano bug di analisi o ottimizzazione relativi alla trasformazione di CASE e TO_ funziona su alcune versioni di Oracle.

Ad esempio, l'istruzione SQL seguente non riesce su 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

Credo che questo sia un bug di analisi o ottimizzazione perché l'errore scompare se interrompi le trasformazioni aggiungendo un predicato come rownum >= 1 . (Quando Oracle vede ROWNUM , presuppone che i risultati debbano essere visualizzati in un certo ordine e non applicherà tante trasformazioni a quel blocco di query.)

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